<scroll-view>

基础滚动组件,支持横向和竖向滚动。当其内容区域比其本身可视区域更大时,允许用户滚动以展示更多内容。

使用指南

横向与纵向滚动

<scroll-view> 支持横向和纵向的滚动,通过 scroll-orientation 属性来实现。 <scroll-view> 固定使用 linear 布局,且布局方向由 scroll-orientation 属性决定。

滚动事件

使用 bindscrollbindscrolltoupper / bindscrolltolower 等事件回调监听滚动进度的变化。

吸顶能力

作为 <scroll-view> 的孩子节点,可以为其设置 sticky, 使得孩子节点在滚动到距离 <scroll-view> 顶部一定位置后,不会继续跟随内容滚动,而是吸附在距离 <scroll-view> 顶部位置处。

TIP

sticky 只能被设置给 <scroll-view> 的直接子节点。

Android only 上需要对 sticky 节点添加属性 flatten={false}

<scroll-view> 的直接子节点只支持 linearsticky。如果需要更复杂的布局,如子节点自适应撑开,则建议给 <scroll-view> 提供一个唯一的子 view,在该唯一的子节点内部实现更健全的 CSS 能力。

<scroll-view scroll-orientation="vertical">
  <view> // do any thing you want
  {...}
  </view>
</scroll-view>

属性

属性名和属性值用于描述元件的行为和外观

scroll-orientation

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

设置 <scroll-view> 滚动方向。

说明
vertical<scroll-view>子节点纵向布局,<scroll-view>本身纵向滚动
horizontal<scroll-view>子节点横向布局,<scroll-view>本身横向滚动

enable-scroll

// DefaultValue: true
enable-scroll?: boolean

设置是否允许手势拖拽滚动。支持动态切换,在下一次手势中生效。禁止滚动时,用户手动不能滚动

说明
true用户手势可以触发滚动
false用户手势不可以触发滚动,但仍能被 scrollTo 等滚动方法直接滚动

initial-scroll-offset

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

设置初次渲染时的内容绝对距离偏移(与 scrollTo 方法中的 offset 概念有所区别),横纵向由 scroll-orientation 决定,仅在第一次 render 执行时起效,不响应后续更改。

TIP

initial-scroll-offset/to-index 会相互覆盖,不能一起使用

initial-scroll-to-index

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

设置初次渲染时定位到的子节点,仅在第一次 render 执行时起效,不响应后续更改。

TIP

initial-scroll-offset/to-index 会相互覆盖,不能一起使用

如果 index 非法(如为负值、超出子节点个数),则设置无效

bounces
iOS only

// DefaultValue: true
bounces?: boolean

开启边缘回弹效果。

upper-threshold

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

设置一个滚动阈值 (单位 px),表示距离顶部或者左边多远时触发 scrolltoupper 事件。

lower-threshold

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

设置一个滚动阈值,表示距离底部或者右边多远时触发 scrolltolower 事件。

scroll-bar-enable

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

开启滚动条,支持动态切换。

TIP

Android only 仅纵向滚动有滚动条
iOS only
支持纵向和横向滚动条

事件

前端可以在组件上绑定相应事件回调来监听组件的运行时行为。

scroll

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

interface scrollEvent extends CustomEvent {
  detail: {
    /**
     * 事件名称
     **/
    type: 'scroll';
    /**
     * 距上次滚动的横向滚动偏移量
     **/
    deltaX: number;
    /**
     * 距上次滚动的纵向滚动偏移量
     **/
    deltaY: number;
    /**
     * 当前横向滚动偏移量
     **/
    scrollLeft: number;
    /**
     * 当前纵向滚动偏移量
     **/
    scrollTop: number;
    /**
     * 当前内容区域高度
     **/
    scrollHeight: number;
    /**
     * 当前内容区域宽度
     **/
    scrollWidth: number;
  };
}

发生滚动时(有/无动画),触发本事件。

TIP
iOS only

如果有回弹 (bounces={true}),则在回弹状态下scrollLeftscrollTop可能为负。

scrolltoupper

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

interface scrollToUpperEvent extends CustomEvent {
  detail: {
    /**
     * 事件名称
     **/
    type: 'scrolltoupper';
    /**
     * 默认值
     **/
    deltaX: 0;
    /**
     * 默认值
     **/
    deltaY: 0;
  };
}

当滚动区域的上/左边的 upperThreshold 规定的区域与可视区域相交时,触发该事件。

scrolltolower

bindscrolltolower = (e: scrollToLowerEvent) => {};
interface bindscrolltolower extends CustomEvent {
  detail: {
    /**
     * 事件名称
     **/
    type: 'scrolltolower';
    /**
     * 默认值
     **/
    deltaX: 0;
    /**
     * 默认值
     **/
    deltaY: 0;
  };
}

当滚动区域的上/左边的 lowerThreshold 规定的区域与可视区域相交时,触发该事件。

scrollend

bindscrollend = (e: scrollEndEvent) => {};
interface scrollEndEvent extends CustomEvent {
  detail: {
    /**
     * 事件名称
     **/
    type: 'scrollend';
    /**
     * 默认值
     **/
    deltaX: 0;
    /**
     * 默认值
     **/
    deltaY: 0;
    /**
     * 当前横向滚动偏移量
     **/
    scrollLeft: number;
    /**
     * 当前纵向滚动偏移量
     **/
    scrollTop: number;
    /**
     * 当前内容区域高度
     **/
    scrollHeight: number;
    /**
     * 当前内容区域宽度
     **/
    scrollWidth: number;
  };
}

滚动结束时触发该事件。

contentsizechanged

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

interface contentSizeChanged extends CustomEvent {
  detail: {
    /**
     * 事件名称
     **/
    type: 'contentsizechanged';
    /**
     * 新内容区域宽度
     **/
    scrollWidth: number;
    /**
     * 新内容区域高度
     **/
    scrollHeight: number;
  };
}

直接子节点组成的内容区域的宽高发生变化时,触发本事件。 本事件会在 <scroll-view> 的内容完成 layout 后触发。如对 <scroll-view> 的子节点进行更新,请在该事件中调用更新后的 scrollTo 等滚动方法。

方法

前端可以通过 SelectorQuery API 执行组件的方法,使用方法如下。

index.js
lynx
  .createSelectorQuery() // 创建 SelectorQuery
  .select('#video') // 指定目标节点的选择器
  .invoke({
    // 指定对目标节点的操作
    method: 'seekTo',
    params: {
      duration: 1000,
    },
    success: function (res) {
      console.log(res);
    },
    fail: function (res) {
      console.log(res.code, res.data);
    },
  })
  .exec(); // 执行查询

scrollTo

<`<scroll-view>`id="scroll"/>
// 目标滚动位置的计算方法:MIN(可滚动区域,child(index).position + offset)
lynx.createSelectorQuery()
  .select(`#scroll`)
  .invoke({
    method: 'scrollTo',
    params: {
      offset: 0, // offset 设置内容偏移量绝对值
      index: 1, // index 目标子节点,如果设置为零,则会滚动 list 的 padding 的距离
      smooth: true // smooth 设置是否平滑滚动
    },
  })
  .exec();

<scroll-view> 的内容定位到特定位置,可以使用子节点序号 index 或绝对定位 offset。以 offset 为参数时,向右为正,向左为负;RTL 模式下正负会被倒转,向左为正,向右为负。

autoScroll

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

lynx.createSelectorQuery()
  .select(`#scroll`)
  .invoke({
     method: 'autoScroll',
      params: {
        rate: 120, // rate 滑动速度,每秒的距离(单位:px/sec)
        start: true // start 设置开始或者停止自动滚动
      },
  })
  .exec();

触发自动滚动。如果 rate 过小会无法滑动。滚动到边界后,会主动停止 autoScroll。如果用户重新反向拖拽到某一个位置,松手后, autoScroll 也不会重新触发自动滚动。

scrollIntoView

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

lynx.createSelectorQuery()
  .select(`#targetnode`)
  .invoke({
    method: 'scrollIntoView',
    params: {
      scrollIntoViewOptions: {
        block: 'center', // 纵向对齐方式: “start" 顶对齐 | "center" 居中对齐 | "end" 底对齐
        inline: 'start', // 横向对齐方式: "start" 左对齐 | "center" 居中对齐 | "end" 右对齐
        behavior: 'smooth', // 'smooth', // "smooth" | "none" 可选,指顶滚动是否带有动画
      },
    },
  })
  .exec();

使 <scroll-view> 滚动到指定子节点。本方法绑定在 <scroll-view> 的任意(直接/非直接)子节点上,而不是 <scroll-view> 本身。

scrollBy

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

lynx.createSelectorQuery()
  .select('#scrollview')
  .invoke({
    method: 'scrollBy',
    params: {
      offset: number, // 滚动的距离, 单位 px
    },
    success(res) {
      console.log('succ ');
    },
    fail(res) {
      console.log('err ');
    },
}).exec();

在现有偏移量基础上滚动的距离,单位 px

性能优化建议

<scroll-view> 会一次性创建所有的子节点,这有可能导致首屏耗时非常严重。可以通过曝光事件驱动它仅创建可见的子节点。

<scroll-view> 没有任何复用机制,如果其内容过多,可能会占用非常大的问题,导致 OOM 等稳定性问题。

数据超过 3 屏时,尽可能的使用 <list> 来优化性能,或者根据曝光事件自行模拟 <VisualizedList> 逻辑。

兼容性

LCD tables only load in the browser

除非另有说明,本项目采用知识共享署名 4.0 国际许可协议进行许可,代码示例采用 Apache License 2.0 许可协议进行许可。