BetterScroll

repository·dev·Indexed 12 days ago

https://github.com/ustbhuangyi/better-scroll

A dependency-free, plain JavaScript plugin for smooth scrolling on mobile and PC devices, inspired by iScroll. It features a highly extensible plugin system with capabilities for infinite scrolling, pull-down/pull-up refresh, carousel effects, mouse-wheel support, and DOM/image observation.

Tokens
53.1K
Snippets
195
Records
248
Agent score
93%

What's inside BetterScroll

  1. What is BetterScroll?

    dev

    BetterScroll is a dependency-free, plain JavaScript plugin designed to solve scrolling issues on mobile devices (with PC support included). It is inspired by iscroll, making its APIs fully compatible with iscroll, while providing extended features and performance optimizations.

    In version 2.X, the library was modularized to support on-demand loading. The @better-scroll/core package contains only the essential scrolling capabilities, while features like pull-up load or pull-down refresh are moved to separate plugins to reduce package size.

  2. Overview of BetterScroll 2.0

    dev

    BetterScroll 2.0 is a native JavaScript scrolling library designed to provide smooth scrolling effects, primarily targeting mobile devices (though PC is supported).

    Key features include:

    • Smooth scrolling effect: Optimized for mobile scrolling experiences.
    • Zero dependence: Built with native JS, making it compatible with any framework including Vue, React, and other MVVM frameworks.
    • Pluggable architecture: Supports a wide range of plugins such as Picker, PullUpLoad, PullDownRefresh, Zoom, Mouse-Wheel, Slide, Movable, Indicators, Parallax Scrolling, and Magnifier.
  3. Slide plugin HTML structure and requirements

    dev

    The slide plugin expects a specific DOM hierarchy:

    <div class="slide-wrapper">
      <div class="slide-content">
        <div class="slide-page"><div></div></div>
        <div class="slide-page"><div></div></div>
      </div>
    </div>
    • slide-wrapper: The main container.
    • slide-content: The scroll element.
    • slide-page: Individual pages.

    Critical Notes:

    • Minimum Pages: slide-content must have at least one slide-page. If there is only one page, loop will not work.
    • Looping: When loop: true, the plugin inserts extra pages before and after the content to create the seamless effect.
    • iOS/iPhone Fix: If experiencing flickering when useTransition: true, add these styles to every .slide-page:
      transform: translate3d(0,0,0);
      backface-visibility: hidden;
  4. How nested-scroll works and how to configure it

    dev

    The nested-scroll plugin coordinates scrolling behavior between multiple BetterScroll instances.

    Setup

    First, register the plugin using the static BScroll.use() method:

    import BScroll from '@better-scroll/core'
    import NestedScroll from '@better-scroll/nested-scroll'
    
    BScroll.use(NestedScroll)

    Configuration

    In versions v2.1.0 and above, you configure nestedScroll within the BetterScroll options using a groupId.

    • Group ID Logic: BetterScroll instances with the same groupId (a string or number) share the same NestedScroll instance. This shared instance coordinates the scrolling behavior of all associated instances.
    • Multi-Nesting: v2.1.0+ supports multi-level nesting and solves the issue where click events are dispatched multiple times in nested structures.

    Note for older versions (< v2.1.0): You must use a boolean nestedScroll: true instead of the object configuration, but this only supports double nesting.

    // >= v2.1.0 configuration
    // parent bs
    new BScroll('.outerWrapper', {
      nestedScroll: {
        groupId: 'shared-group-id'
      }
    })
    
    // child bs
    new BScroll('.innerWrapper', {
      nestedScroll: {
        groupId: 'shared-group-id'
      }
    })
  5. Listen to BetterScroll events and hooks

    dev

    BetterScroll uses an EventEmitter pattern for both standard events and internal hooks.

    Events vs Hooks

    • Events: Used for compatibility with version 1.x. These are attached directly to the BScroll instance. Use these for general usage (e.g., scroll, scrollEnd, refresh).
    • Hooks: Used primarily for plugin development. These are attached to the bs.hooks property. Use these to tap into internal lifecycle stages (e.g., enable, refresh).

    Event Methods

    • on(type, fn, context): Listen for an event.
    • once(type, fn, context): Listen for an event only once.
    • off(type, fn): Remove a specific event listener.
    import BScroll from '@BetterScroll/core'
    let scroll = new BScroll('.wrapper', {
      probeType: 3
    })
    
    // Using Events (1.x compatibility)
    function onScroll(pos) {
        console.log(`Now position is x: ${pos.x}, y: ${pos.y}`)
    }
    scroll.on('scroll', onScroll)
    
    // Using Hooks (for plugins)
    scroll.hooks.on('refresh', () => {
      console.log('Internal refresh hook triggered')
    })
  6. How BetterScroll scrolling works

    dev

    BetterScroll requires a specific HTML structure to function correctly. It relies on a parent container (wrapper) and a child element (content).

    Requirements:

    1. Wrapper (Parent): Must have a fixed height.
    2. Content (First Child): The height of the content element must be greater than the wrapper's height to enable scrolling.

    By default, BetterScroll treats the first child element of the wrapper as the scrollable content. Other elements inside the wrapper are ignored.

    HTML Structure Example:

    <div class="wrapper">
      <ul class="content">
        <li>...</li>
        <li>...</li>
      </ul>
      <!-- Other DOM elements here will be ignored by the scroll engine -->
    </div>
    <div class="wrapper">
      <ul class="content">
        <li>...</li>
        <li>...</li>
      </ul>
    </div>
  7. Use mouseWheel with other plugins

    dev

    The mouseWheel plugin can be combined with other BetterScroll plugins to enhance functionality:

    • mouseWheel & slide: Enables operating slide components using the mouse wheel.
    • mouseWheel & pullup: Enables using the mouse wheel to trigger pullup operations.
    • mouseWheel & pulldown: Enables using the mouse wheel to trigger pulldown operations.
    • mouseWheel & wheel: Enables using the mouse wheel to trigger wheel operations.
  8. Handle the pullingUp event and finishPullUp()

    dev

    The pullingUp event is triggered when the scroll distance to the bottom is less than the configured threshold.

    CRITICAL: The pullingUp event can only be consumed once per detection. After the event triggers, you must call bs.finishPullUp() to signal to BetterScroll that the current pull-up action is complete and it should prepare for the next pullingUp event.

    const bs = new BScroll('.wrapper', {
      pullUpLoad: {
        threshold: 0
      }
    })
    
    bs.on('pullingUp', () => {
      // Perform your data loading logic here...
      
      // IMPORTANT: Tell BetterScroll to allow the next pullingUp event
      bs.finishPullUp()
    })
  9. How the PullDown lifecycle and states work

    dev

    The pull-down process follows a specific state machine. Understanding these states is crucial for managing UI feedback (like 'Pull down to refresh' text) and data fetching.

    1. default: The initial state.
    2. moving: The user is actively pulling. During this state, two events are dispatched:
      • enterThreshold: Dispatched when the pull distance enters the threshold area. Use this to show 'Pull down to refresh' prompts.
      • leaveThreshold: Dispatched when the pull distance leaves the threshold area. Use this to show 'Release finger' prompts.
    3. fetching: Triggered after the user releases their finger if the threshold was met. This is when you execute your data fetching logic.

    State transitions: default -> moving -> fetching or default -> moving (if the threshold wasn't met upon release).

  10. How the infinity plugin works

    dev

    The infinity plugin provides unlimited scrolling. Instead of rendering a massive list of DOM elements at once, BetterScroll only renders a specific number of elements, recycling them as the user scrolls. This allows for smooth scrolling even with very large datasets.

    Note: Only use this plugin if you have significant data rendering needs; otherwise, use the core BScroll functionality.

  11. Extend BetterScroll with Plugins

    dev

    BetterScroll's core functionality can be enhanced using plugins. For example, to enable pull-up loading, you must import the @better-scroll/pull-up plugin and enable the pullUpLoad option in the configuration object.

    import BScroll from '@better-scroll/core'
    import PullUp from '@better-scroll/pull-up'
    
    let bs = new BScroll('.wrapper', {
      pullUpLoad: true
    })
  12. Configure freeScroll and directionLockThreshold

    dev

    BetterScroll typically locks scrolling to a single direction to prevent accidental diagonal movement. You can control this behavior with these options:

    • freeScroll (boolean, default: false): When true, BetterScroll calculates both horizontal and vertical offsets simultaneously, allowing diagonal movement. This is invalid if eventPassthrough is set.
    • directionLockThreshold (number, default: 5): When freeScroll is false, this value determines the threshold for locking direction. If the difference between absolute horizontal and vertical movement exceeds this value, the direction is locked. Note: If eventPassthrough is set, this option is invalid and defaults to 0.