Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

TIP 👉 To the country of life and death, not because of fortune and misfortune to avoid! ____ Lin Zexu, “Going to The Garrison on a Journey to Occupy his Family · Ii”

preface

In our daily project development, we often encounter some scroll operations, so the package of this scroll component.

Scroll to the component

better-scroll.github.io/docs/zh-CN/

1. The attribute

ScrollX – Whether horizontal scrolling is enabled
  • Types: Boolean
  • Default value: false
ScrollY – Whether to enable vertical scrolling
  • Types: Boolean
  • Default value: true
Scrollbar – whether to display a scrollbar
  • Types: Boolean
  • Default value: true
MouseWheel – whether mouseWheel is supported
  • Types: Boolean | Object
  • Default value: true
  • Example values of the Object type:
    {
      speed: 20.invert: false.easeTime: 300.discreteTime: 400.throttleTime: 0.dampingFactor: 0.1
    }
    Copy the code
Bounce – Whether to display bounce animations
  • Types: Boolean | Object
  • Default value: false
  • Example values of the Object type:
    {
        top: true.bottom: true.left: true.right: true
      }
    Copy the code
NestedScroll – Whether to nest scrollbars in multiple layers
  • Types: Boolean | Object
  • Default value: false
  • Example values of the Object type:
    { groupId: 'dummy-divide' }
    Copy the code
PullDownRefresh – Whether pull-down refresh is supported
  • Types: Boolean | Object
  • Default value: false
  • Example values of the Object type:
    {
      threshold: 90.stop: 40
    }
    Copy the code
PullUpLoad – Whether pull-up loading is supported
  • Types: Boolean | Object
  • Default value: false
  • Example values of the Object type:
    {
      threshold: 0
    }
    Copy the code
WrapperBgColor – Wrapper back scene (pull up, pull down leaking background color)
  • Type: String
  • Default value: transparent
  • Note: This parameter is not a BetterScroll configuration item
ContentBgColor – Content Area background color (dropdown and dropdown background color)
  • Type: String
  • Default value: transparent
  • Note: This parameter is not a BetterScroll configuration item
EventId – The ID of the reinitialization scrollbar event
  • Type: String
  • No default value
  • Note: This parameter is not a BetterScroll configuration item
  • Trigger a reinitialization scrollbar event in another component
    this.$eventBus.$emit('init-scroll-' + this.scrollEventId)
    Copy the code
  • Trigger the refresh scrollbar event in another component
    this.$eventBus.$emit('refresh-scroll-' + this.scrollEventId)
    Copy the code
Stretch – Whether to stretch the first child of the content area (set the min-height of the first child to the height of the wrapped area)
  • Types: Boolean
  • Default value: false
  • Note: This parameter is not a BetterScroll configuration item
ObserveDOM – Whether to enable detection of DOM changes
  • Types: Boolean
  • Default value: true
ObserveImage – Enables image element loading probes
  • Types: Boolean
  • Default value: false
ProbeType – When scroll event is sent
  • Type: Number
  • Default value: 0
  • Description:
    • ProbeType is 0, the Scroll event is not sent at any time,
    • ProbeType is 1, just send scroll event once every momentumLimitTime milliseconds when finger is pressed on scroll area,
    • ProbeType is 2, only when the finger presses on the scroll area and keeps sending scroll events,
    • ProbeType is 3, and scroll events are distributed at any time, including calling scrollTo or triggering momentum scrolling animation
EventPassthrough – Preserves the native scrolling direction
  • Type: String
  • Default value:”
  • Optional value:
    • ‘vertical’: retain vertical native scrolling
    • ‘Horizontal ‘: Retains horizontal native scrolling
Click – Whether to issue a click event when clicked
  • Types: Boolean
  • Default value: true
StopPropagation – Whether to prevent event bubblers
  • Types: Boolean
  • Default value: false
BounceTime – The animation duration of the rebound animation (in ms)
  • Type: Number
  • Default value: 800
UseTransition – Whether to animate CSS3 Transition (if set to false, use requestAnimationFrame)
  • Types: Boolean
  • Default value: true

2. Style requirements

  • The component needs to be wrapped around elements that can be positioned relative to each other. Add styles:position: relative
<template>
  <div class="scroll-parent">
    <Scroll>
      <! Scrollable area content -->
    </Scroll>
  </div>
</template>
<script>
import Scroll from '@/components/base/scroll'
export default {
  components: {
    Scroll
  }
}
</script>
<style lang="scss" scoped>
.scroll-parent {
  position: relative;
  height: 100px;
}
</style>
Copy the code
  • In the example, the size of the scrollable area for the scrollable parent, position is relative, is the same as the size of the element

A simple example

<template>
  <scroll :bounce="false" :observeImage="true" wrapperBgColor="#f9f9f9" contentBgColor="#fff">
    <div>
      <img src="https://tinypng.com/images/panda-confetti.png" alt=""><br>
      <img src="https://tinypng.com/images/bamboo.png" alt=""><br>
      <img src="https://tinypng.com/images/apng/panda-waving.png" alt=""><br>
      <h1>1</h1>
      <h1>2</h1>
      <h1>3</h1>
      <h1>4</h1>
      <h1>5</h1>
      <h1>6</h1>
      <h1>7</h1>
      <h1>8</h1>
      <h1>9</h1>
      <h1>10</h1>
    </div>
  </scroll>
</template>
<script>
import Scroll from '@/components/base/scroll'
export default {
  components: {
    Scroll
  }
}
</script>
Copy the code

Two, the horizontal scroll example

1. Related attributes

  • ScrollX – Whether horizontal scrolling is supported
  • ScrollY – Whether vertical scrolling is supported

2. Style requirements

  • The content must be inline and cannot be folded
<template>
  <div class="nav-wrap">
    <scroll :scrollbar="false" :bounce="true" :scrollX="true" :scrollY="false">
      <ul class="nav">
        <li>recommended</li>
        <li>entertainment</li>
        <li>video</li>
        <li>life</li>
        <li>information</li>
        <li>fashion</li>
        <li>Beauty makeup</li>
        <li>health</li>
        <li>sports</li>
      </ul>
    </scroll>
  </div>
</template>
<script>
import Scroll from '@/components/base/scroll'
export default {
  name: 'ScrollHorizontal'.components: {
    Scroll
  }
}
</script>
<style lang="scss" scoped>$nav-height: 92px; .nav-wrap{ position: relative; height: $nav-height; } .nav{ display: inline-flex; flex-wrap: nowrap; height: $nav-height; min-width: 750px; padding: 0 30px; background-color: #f5fffc; list-style: none; li { line-height: $nav-height; font-size: 36px; text-align: center; white-space: nowrap; padding: 0 40px; }}</style>
Copy the code

Three, scroll bar nesting

1. Related attributes

  • NestedScroll – Whether to nest scrollbars in multiple layers
    • Note: This property is required for cohoming, not for non-cohoming
<template>
  <scroll :bounce="true" :observeImage="true"
          wrapperBgColor="#f9f9f9" contentBgColor="#fff" :nestedScroll="{ groupId: 'myGroup' }">
    <div class="page-content">
      <h1>1</h1>
      <h1>2</h1>
      <h1>3</h1>
      <h1>4</h1>
      <h1>5</h1>
      <div class="vertical-wrapper">
        <scroll :bounce="true" :nestedScroll="{ groupId: 'myGroup' }">
          <div class="vertical">
            <div>1</div>
            <div>2</div>
            <div>3</div>
            <div>4</div>
            <div>5</div>
            <div>6</div>
            <div>7</div>
            <div>8</div>
            <div>9</div>
            <div>10</div>
          </div>
        </scroll>
      </div>
      <h1>6</h1>
      <h1>7</h1>
      <h1>8</h1>
      <h1>9</h1>
      <h1>10</h1>
      <div class="horizontal-wrapper">
        <scroll :bounce="true" :scrollX="true" :scrollY="false">
          <div class="horizontal">
            <div>1</div>
            <div>2</div>
            <div>3</div>
            <div>4</div>
            <div>5</div>
            <div>6</div>
            <div>7</div>
            <div>8</div>
            <div>9</div>
            <div>10</div>
          </div>
        </scroll>
      </div>
      <h1>11</h1>
      <h1>12</h1>
      <h1>13</h1>
      <h1>14</h1>
      <h1>15</h1>
    </div>
  </scroll>
</template>
<script>
import Scroll from '@/components/base/scroll'
export default {
  name: 'ScrollNested'.components: {
    Scroll
  }
}
</script>
Copy the code

Refresh the scroll bar example

When the scrollbar component is nested in multiple layers, the scrollbar can be refreshed through global EventBus when it needs to be refreshed.

1. Related attributes

1) eventId

Event ID

2. Execution mode

  • Publish the reinitialization scrollbar event named ‘refresh-Scroll -‘ + eventId through the global EventBus
<scroll eventId="myScroll">... </scroll>Copy the code
// Other components trigger scrollbar refreshes
this.$eventBus.$emit('refresh-scroll-myScroll')
Copy the code

5. Reinitialize the scroll bar example

When the scrollbar component is nested in multiple layers, you can use the global EventBus to reinitialize the scrollbar if the scrollbar parameters change.

1. Related attributes

1) eventId

Event ID

2. Execution mode

  • Publish the reinitialization scrollbar event with the name ‘init-scroll-‘ + eventId through the global EventBus
  • The event parameter is Boolean: if true, indicates the position of the scroll bar to be held during reinitialization
<scroll eventId="myScroll">... </scroll>Copy the code
// Other components trigger a scrollbar reinitialization, leaving the scrollbar position unchanged
this.$eventBus.$emit('init-scroll-myScroll'.true)
Copy the code

Implement a scroll.vue

<template>
  <div ref="wrapper" class="scroll-wrapper" :style="wrapperStyle" @touchmove="propagationFilter">
    <div class="scroll-content" :style="contentStyle" ref="content">
      <slot></slot>
    </div>
  </div>
</template>

<script>
import BScroll from '@better-scroll/core'
import MouseWheel from '@better-scroll/mouse-wheel'
import ScrollBar from '@better-scroll/scroll-bar'
import ObserveDOM from '@better-scroll/observe-dom'
import ObserveImage from '@better-scroll/observe-image'
import NestedScroll from '@better-scroll/nested-scroll'
import PullDown from '@better-scroll/pull-down'
import Pullup from '@better-scroll/pull-up'

BScroll.use(ScrollBar)
BScroll.use(MouseWheel)
BScroll.use(ObserveDOM)
BScroll.use(ObserveImage)
BScroll.use(NestedScroll)
BScroll.use(PullDown)
BScroll.use(Pullup)

export default {
  name: 'scroll'.props: {
    // Whether to enable horizontal scrolling
    scrollX: {
      type: Boolean.default: false
    },
    // Whether to enable vertical scrolling
    scrollY: {
      type: Boolean.default: true
    },
    // Whether to display a scroll bar
    scrollbar: {
      type: Boolean.default: true
    },
    // Whether mouse wheel is supported
    /* Object examples: {speed: 20, invert: false, easeTime: 300, discreteTime: 400, throttleTime: 0, dampingFactor: 0.1} */
    mouseWheel: {
      type: [Boolean.Object].default: true
    },
    // Whether to display the rebound animation
    /* Object examples: {top: true, bottom: true, left: true, right: true} */
    bounce: {
      type: [Boolean.Object].default: false
    },
    // Whether the scrollbar is nested multilayer
    /* Object instance: {groupId: 'dummy-divide'} */
    nestedScroll: {
      type: [Boolean.Object].default: false
    },
    // Whether pull-down refresh is supported
    pullDownRefresh: {
      type: [Boolean.Object].default: false
    },
    // Whether pull-up loading is supported
    pullUpLoad: {
      type: [Boolean.Object].default: false
    },
    /** * [non-BetterScroll configuration item] Backcolor of the wrapper (the background color that is leaked from the dropdown and up) */
    wrapperBgColor: {
      type: String.default: 'transparent'
    },
    /** * [non-BetterScroll configuration item] Content area background color */
    contentBgColor: {
      type: String.default: 'transparent'
    },
    /** * [non-BetterScroll configuration item] ID of the reinitialization scrollbar event */
    eventId: {
      type: String.default: null
    },
    // [non-BetterScroll configuration item] Whether to stretch the first child of the content area (set the min-height of the first child to the height of the enclosing area)
    stretch: {
      type: Boolean.default: false
    },
    // Whether to enable detection of content and content child DOM changes
    observeDOM: {
      type: Boolean.default: true
    },
    // Enable probing for loading of image elements in the Wrapper child
    // [Note] : This plug-in should not be used for scenarios where CSS has been used to determine the image width and height, because each call to Refresh has an impact on performance. You only need it if the width or height of the image is uncertain.
    observeImage: {
      type: Boolean.default: false
    },
    /** * 1. ProbeType = 1, only send scroll events once every momentumLimitTime milliseconds when finger is pressed on the scroll area, * 3. ProbeType is 2, only when the finger presses on the scroll area, always send scroll event, * 4. ProbeType is 3, always send Scroll event, This includes calling scrollTo or triggering a momentum scrolling animation */
    probeType: {
      type: Number.default: 0
    },
    /** * Retain the original scroll direction, with options: 'vertical', 'horizontal' */
    eventPassthrough: {
      type: String.default: ' '
    },
    BetterScroll will block the browser's native Click event by default. When set to true, BetterScroll will send a click event, and we'll add a private _constructed property to the event argument to create a value of true */
    click: {
      type: Boolean.default: true
    },
    // Whether to prevent events from bubbling
    stopPropagation: {
      type: Boolean.default: false
    },
    // The animation duration of the rebound animation (unit :ms)
    bounceTime: {
      type: Number.default: 800
    },
    // Whether to animate CSS3 Transition (if set to false, use requestAnimationFrame)
    useTransition: {
      type: Boolean.default: true
    }
  },
  data () {
    return {
      bs: null BetterScroll instance object}},computed: {
    wrapperStyle () {
      return { backgroundColor: this.wrapperBgColor }
    },
    contentStyle () {
      let contentStyle = { backgroundColor: this.contentBgColor }
      if (this.scrollX) {
        contentStyle.display = 'inline-block'
      }
      return contentStyle
    }
  },
  created () {
    if (this.eventId) {
      this.$eventBus.$on('init-scroll-' + this.eventId, holdPosition= > {
        this.initScroll(holdPosition)
      })
      this.$eventBus.$on('refresh-scroll-' + this.eventId, holdPosition= > {
        this.refresh()
      })
    }
  },
  mounted () {
    this.$nextTick(() = > {
      if (this.stretch) {
        this.stretchContentChild() // Stretch the height of the first child of the content area
      }
      this.initScroll()
    })
  },
  beforeDestroy () {
    if (this.eventId) {
      this.$eventBus.$off('init-scroll-' + this.eventId)
      this.$eventBus.$off('refresh-scroll-' + this.eventId)
    }
    if (this.bs) {
      this.bs.destroy()
    }
  },
  methods: {
    /** * Initializes the scrollbar * holdPosition Specifies whether to hold the scrollbar position. Default: false, the scrollbar is at the top or left after reinitialization
    initScroll (holdPosition = false) {
      // console.log('initScroll')
      // Start position of scroll bar
      let startX = 0
      let startY = 0
      if (this.bs) {
        // Whether to hold the scrollbar position
        if (holdPosition) {
          startX = this.bs.x
          startY = this.bs.y
        }
        // Destroy the original scroll bar and unbind the event
        this.bs.destroy()
      }

      let options = {
        startX,
        startY,
        scrollX: this.scrollX, // Whether to enable horizontal scrolling
        scrollY: this.scrollY, // Whether to enable vertical scrolling
        bounce: this.bounce, // Whether to display the rebound animation
        probeType: this.probeType, // When to send scroll event
        click: this.click, // Whether to block the browser's native click event
        stopPropagation: this.stopPropagation, // Whether to prevent events from bubbling
        eventPassthrough: this.eventPassthrough // Keep native scrolling in one direction
      }
      // bug: The option of the plugin class. The plugin still works when the value is false. Configuration items are added only when the value is set to true
      // Whether to display a scroll bar
      if (this.scrollbar) {
        options.scrollbar = this.scrollbar
      }
      // Whether mouse wheel is supported
      if (this.mouseWheel) {
        options.mouseWheel = (this.mouseWheel === true)? {speed: 20.invert: false.easeTime: 300 } : this.mouseWheel
      }
      // Whether to enable detection of DOM changes
      if (this.observeDOM) {
        options.observeDOM = this.observeDOM
      }
      // Whether to enable probe for image loading
      if (this.observeImage) {
        options.observeImage = this.observeImage
      }
      // Whether scroll bars are nested
      if (this.nestedScroll) {
        options.nestedScroll = this.nestedScroll
      }
      // Whether pull-down refresh is supported
      if (this.pullDownRefresh) {
        options.pullDownRefresh = this.pullDownRefresh
      }
      // Whether pull-up loading is supported
      if (this.pullUpLoad) {
        options.pullUpLoad = this.pullUpLoad
      }

      console.log('Scrollbar initial configuration:', options)
      // Create BetterScroll again
      const bs = new BScroll(this.$refs.wrapper, options)
      this.bs = bs
      this.$emit('created', bs)
      this.bs.hooks.on('refresh'.() = > { console.log('Scrollbar Refresh' + new Date()) })
    },
    disable () {
      this.bs && this.bs.disable()
    },
    enable () {
      this.bs && this.bs.enable()
    },
    refresh () {
      this.bs && this.bs.refresh()
    },
    // Stretch the content area (the minimum height of the child element of the content area is set to the height of the wrapping area)
    stretchContentChild () {
      let wrapperHeight = this.$refs.wrapper.getBoundingClientRect().height
      let children = this.$refs.content.children
      if (wrapperHeight && children && children.length === 1) {
        let child = children[0]
        child.style.minHeight = wrapperHeight + 'px'}},// Event bubbling filters
    propagationFilter (e) {
      if (e.target && e.target.tagName === 'TEXTAREA') { // Textarea prevents bubbling
        e.stopPropagation()
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.scroll-wrapper {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  overflow: hidden;
}
.scroll-content {
  min-height: 100%;
  &:before {
    content: ' ';
    display: table;
  }
  &:after {
    content: ' ';
    display: table;
    clear: both; }}.pulldown-wrapper {
  position: absolute;
  width: 100%;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  transition: all;
}
.pullup-wrapper {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 16px 0;
}
.pulldown {
  position: absolute;
  top: 0;
  left: 0;
}
.pulldown-enter-active {
  transition: all 0.2 s;
}
.pulldown-enter..pulldown-leave-active {
  transform: translateY(-100%);
  transition: all 0.2 s;
}
.tip-msg {
  position: absolute;
  width: 100%;
  text-align: center;
}
::v-deep .bscroll-vertical-scrollbar{
  width: 10px ! important;
}
::v-deep .bscroll-horizontal-scrollbar {
  height: 10px ! important;
}
</style>
Copy the code

index.js

/** * Scrollbar component *@see https://github.com/ustbhuangyi/better-scroll
 * @see https://better-scroll.github.io/docs/zh-CN/
 */
import Scroll from './Scroll.vue'
export default Scroll
Copy the code

Thanks for the comment section.

Hope to finish watching friends can give a thumbs-up, encourage once