<scroll-view>

Basic scrolling component supporting both horizontal and vertical scrolling. When its content area is larger than its visible area, it allows users to scroll to reveal more content.

Usage

Horizontal and Vertical Scrolling

<scroll-view> supports both horizontal and vertical scrolling, implemented through the scroll-orientation properties. <scroll-view> always uses the linear layout, and the layout direction is determined by the scroll-orientation attributes.

Scroll Events

Use event callbacks such as bindscroll, bindscrolltoupper, and bindscrolltolower to monitor changes in scroll progress.

Sticky Capability

As a child node of <scroll-view>, you can set the sticky attribute making the child node remain at a certain distance from the top of the <scroll-view> and not continue scrolling with the content.

TIP

sticky can only be set for direct child nodes of <scroll-view>. On

Android only, you need to add the flatten={false} attribute to sticky nodes.

The direct child nodes of <scroll-view> only support linear and sticky. If you need more complex layouts, such as child nodes adapting to expand, it is recommended to provide a single child view to the <scroll-view> and implement more robust CSS capabilities within that single child node.

<scroll-view> scroll-y>
  <view> // do anything you want
  {...}
  </view>
</scroll-view>

Attributes

Attribute names and values describe the behavior and appearance of the component.

scroll-orientation

// DefaultValue: "vertical"
scroll-orientation?: string

set scroll orientation for the scrollable container.

说明
verticalChild nodes are arranged vertically, causing <scroll-view> itself to scroll vertically
horizontalChild nodes are arranged horizontally, causing <scroll-view> itself to scroll horizontally

enable-scroll

// DefaultValue: true
enable-scroll?: boolean

Sets whether to allow gesture dragging to scroll. Supports dynamic switching and takes effect on the next gesture. When scrolling is disabled, the user cannot scroll manually.

ValueDescription
trueUser gestures can trigger scrolling
falseUser gestures cannot trigger scrolling but scrolling methods (e.g., scrollTo) can still initiate scrolling

initial-scroll-offset

// DefaultValue: N/A
initial-scroll-top?: string = ${number}px

Sets the absolute content offset distance during initial rendering (different from the offset concept in the scrollTo method). The horizontal or vertical direction is determined by scroll-orientation, and it only takes effect during the first render execution, not responding to subsequent changes.

TIP

Cannot be used simultaneously with initial-scroll-offset/to-index as they will cover each other.

initial-scroll-to-index

// DefaultValue: N/A
initial-scroll-to-index?: string = ${number}px

Sets the child node to be positioned during initial rendering, only taking effect during the first render execution and not responding to subsequent changes.

TIP

Cannot be used simultaneously with initial-scroll-offset/to-index as they will cover each other.

If the index is invalid (e.g., negative or exceeds the number of child nodes), the setting is ineffective.

bounces
iOS only

// DefaultValue: true
bounces?: boolean

Enables edge bounce effect.

upper-threshold

// DefaultValue: N/A
upper-threshold?: string = ${number}px

Sets a scroll threshold (unit: px), indicating how far from the top or left before triggering the scrolltoupper event.

lower-threshold

// DefaultValue: N/A
lower-threshold?: string = ${number}px

Sets a scroll threshold, indicating how far from the bottom or right before triggering the scrolltolower event.

scroll-bar-enable

// DefaultValue: false
scroll-bar-enable?: boolean

Enables the scrollbar, supporting dynamic switching.

TIP

Android only Only vertical scrolling has scrollbars.
iOS only
Supports both vertical and horizontal scrollbars.

Events

Frontend can bind corresponding event callbacks to components to monitor their runtime behavior.

scroll

bindscroll = (e: scrollEvent) => {};

interface scrollEvent extends CustomEvent {
  detail: {
    type: 'scroll'; // Event name
    deltaX: number; // Horizontal scroll offset since last scroll
    deltaY: number; // Vertical scroll offset since last scroll
    scrollLeft: number; // Current horizontal scroll offset
    scrollTop: number; // Current vertical scroll offset
    scrollHeight: number; // Current content height
    scrollWidth: number; // Current content width
  };
}

Triggered during scrolling (whether animated or not).

TIP
iOS only

If there is a bounce (bounces={true}), scrollLeft and scrollTop may be negative during the bounce.

scrolltoupper

bindscrolltoupper = (e: scrollToUpperEvent) => {};

interface scrollToUpperEvent extends CustomEvent {
  detail: {
    type: 'scrolltoupper'; // Event name
    deltaX: 0; // Default value
    deltaY: 0; // Default value
  };
}

Triggered when the defined upperThreshold area intersecting the visible area at the top or left.

scrolltolower

bindscrolltolower = (e: scrollToLowerEvent) => {};

interface scrollToLowerEvent extends CustomEvent {
  detail: {
    type: 'scrolltolower'; // Event name
    deltaX: 0; // Default value
    deltaY: 0; // Default value
  };
}

Triggered when the defined lowerThreshold area intersects the visible area at the bottom or right.

scrollend

bindscrollend = (e: scrollEndEvent) => {};

interface scrollEndEvent extends CustomEvent {
  detail: {
    type: 'scrollend'; // Event name
    deltaX: 0; // Default value
    deltaY: 0; // Default value
    scrollLeft: number; // Current horizontal scroll offset
    scrollTop: number; // Current vertical scroll offset
    scrollHeight: number; // Current content height
    scrollWidth: number; // Current content width
  };
}

Triggered when scrolling ends.

contentsizechanged

bindcontentsizechanged = (e: contentSizeChanged) => {};

interface contentSizeChanged extends CustomEvent {
  detail: {
    type: 'contentsizechanged'; // Event name
    scrollWidth: number; // New content width
    scrollHeight: number; // New content height
  };
}

Triggered when the content area comprised of direct child nodes changes in width or height. This event triggers after the <scroll-view> content completes layout. If updating <scroll-view> child nodes, call updated scrolling methods like scrollTo in this event.

Methods

Frontend can execute component methods through the SelectorQuery API, using the following methods:

index.js
lynx
  .createSelectorQuery() // Create SelectorQuery
  .select('#video') // Specify target node selector
  .invoke({
    method: 'seekTo',
    params: {
      duration: 1000, // Operation parameters
    },
    success: function (res) {
      console.log(res);
    },
    fail: function (res) {
      console.log(res.code, res.data);
    },
  })
  .exec(); // Execute query

scrollTo

<`<scroll-view>`id="scroll"/>
// Target scrolling position calculation: MIN(scrollable area, child(index).position + offset)
lynx.createSelectorQuery()
  .select(`#scroll`)
  .invoke({
    method: 'scrollTo',
    params: {
      offset: 0, // Absolute offset value
      index: 1, // Target child node, positions to list's padding distance if set to zero
      smooth: true // Whether to smoothly scroll
    },
  })
  .exec();

Positions the <scroll-view> content to a specific location, using either the child node index index or an absolute offset offset. For the offset parameter, positive is right, negative is left; in RTL mode, positive-negative reverses, positive is left, negative is right.

autoScroll

<`<scroll-view>`id="scroll"/>

lynx.createSelectorQuery()
  .select(`#scroll`)
  .invoke({
     method: 'autoScroll',
      params: {
        rate: 120, // Scrolling speed, distance per second (unit: px/sec)
        start: true // Start or stop auto-scrolling
      },
  })
  .exec();

Triggers automatic scrolling. If the rate is too small, it may not scroll. Upon reaching the boundary, autoScroll will stop automatically. If the user drags in the opposite direction to a certain position and releases, autoScroll will not re-trigger auto-scrolling.

scrollIntoView

<scroll-view>
  <text id="targetnode">"click me, scrollIntoView"</text>
</scroll-view>

lynx.createSelectorQuery()
  .select(`#targetnode`)
  .invoke({
    method: 'scrollIntoView',
    params: {
      scrollIntoViewOptions: {
        block: 'center', // Vertical alignment options: "start" aligns top | "center" centers | "end" aligns bottom
        inline: 'start', // Horizontal alignment options: "start" aligns left | "center" centers | "end" aligns right
        behavior: 'smooth', // "smooth" | "none" whether to animate scrolling
      },
    },
  })
  .exec();

Scrolls the <scroll-view> to the specified child node. This method is bound to any (direct/indirect) child node of <scroll-view>, not <scroll-view> itself.

scrollBy

<`<scroll-view>`id="scrollview"/>

lynx.createSelectorQuery()
  .select('#scrollview')
  .invoke({
    method: 'scrollBy',
    params: {
      offset: number, // Scroll distance, unit: px
    },
    success(res) {
      console.log('succ ');
    },
    fail(res) {
      console.log('err ');
    },
}).exec();

Scrolls by the distance based on existing offsets, unit px.

Performance Optimization Suggestions

<scroll-view> creates all of its child nodes at once, potentially causing severe first-screen load times. Use exposure events to drive it to create only visible child nodes.

<scroll-view> lacks any reuse mechanism. If content is too extensive, it may consume an exceptionally large amount of memory, possibly causing OOM and other stability problems.

For data exceeding three screens, use <list> to optimize performance, or simulate <VisualizedList> logic based on exposure events.

Compatibility

LCD tables only load in the browser

Except as otherwise noted, this work is licensed under a Creative Commons Attribution 4.0 International License, and code samples are licensed under the Apache License 2.0.