组件/Scroll 滚动
通用组件

Scroll 滚动

基于 `@better-scroll/scroll-bar` 的当前 `TxScroll` 滚动容器,提供更一致的滚动条体验。

该页面由 AI 迁移生成,请谨慎使用

内容已迁移完成,但仍建议结合源码和人工评审结果使用。

Scroll 滚动

基于 @better-scroll/scroll-bar 的当前 TxScroll 滚动容器,提供更一致的滚动条体验。

行为说明

  • BetterScroll 模式
    • 支持 bounce、更一致的滚动条外观
    • 内容/容器变化会自动 refresh()(可通过 refreshOnContentChange 控制)
  • Native 模式
    • 使用浏览器原生滚动
    • direction 会映射为 overflow-x/y 以保持结构一致
    • macOS Safari 直接启用原生滚动
    • 默认在 macOS + Chromium 145+ 自动回退到原生滚动(Chromium 原生已支持)
    • 如需跨环境统一由 BetterScroll 接管,可设置 unified=true

运行时策略(优先级)

  1. native=true:始终使用原生滚动(最高优先级)。
  2. unified=true:始终由 BetterScroll 接管(跨环境统一行为)。
  3. 运行在 macOS Safari:直接使用原生滚动。
  4. nativeAutoFallback=true 且满足 macOS + Chromium >= 145:自动使用原生滚动。
  5. 其他情况:使用 BetterScroll。

基础用法

Scroll

示例即将加载...
<template>
  <div class="demo-container" style="height: 220px;">
    <div style="height: 100%;">
      <TxScroll style="height: 100%;">
        <div style="height: 1200px; display: flex; flex-direction: column; gap: 8px;">
          <div v-for="i in 60" :key="i" class="demo-scroll-item">
            Row {{ i }}
          </div>
        </div>
      </TxScroll>
    </div>
  </div>
</template>

方向与滚动条

Scroll (horizontal)

示例即将加载...
<template>
  <div class="demo-container" style="height: 140px;">
    <div style="height: 100%;">
      <TxScroll direction="horizontal" style="height: 100%;">
        <div style="width: 920px; height: 100%; display: flex; align-items: center; gap: 12px;">
          <div v-for="i in 24" :key="i" class="demo-scroll-item" style="min-width: 120px;">
            Col {{ i }}
          </div>
        </div>
      </TxScroll>
    </div>
  </div>
</template>

Scroll (bounce + always show scrollbar)

示例即将加载...
<template>
  <div class="demo-container" style="height: 220px;">
    <div style="height: 100%;">
      <TxScroll :bounce="true" :scrollbar-always-visible="true" style="height: 100%;">
        <div style="height: 160px; display: flex; flex-direction: column; gap: 8px;">
          <div class="demo-scroll-item">
            Short content
          </div>
          <div class="demo-scroll-item">
            No boundary but scrollbar should be visible
          </div>
        </div>
      </TxScroll>
    </div>
  </div>
</template>

滚动链(高级 / Scroll Chaining)

默认会阻止内层滚动把外层一起带着滚动(到边界时也不会继续传递)。如果你希望滚到顶/底后继续滚动外层,需要显式开启 scrollChaining

⚠️ 不建议默认开启 scrollChaining。在复杂嵌套滚动场景中,它容易让用户误判“当前正在滚动哪一层”,仅建议在明确需要父子联动滚动时按需启用。

Scroll (scroll chaining, advanced)

示例即将加载...
<template>
  <div class="demo-container" style="height: 320px;">
    <div style="height: 100%; overflow: auto; padding: 12px; border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.12);">
      <div style="height: 720px; display: flex; flex-direction: column; gap: 12px;">
        <div class="demo-scroll-item">
          Outer scroll area (top)
        </div>

        <div style="height: 160px; border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.12); overflow: hidden;">
          <TxScroll style="height: 100%;" :bounce="true">
            <div style="height: 520px; display: flex; flex-direction: column; gap: 8px;">
              <div class="demo-scroll-item">
                Inner (default): scrollChaining = false
              </div>
              <div v-for="i in 18" :key="i" class="demo-scroll-item">
                Item {{ i }}
              </div>
            </div>
          </TxScroll>
        </div>

        <div class="demo-scroll-item">
          Outer content (middle)
        </div>

        <div style="height: 160px; border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.12); overflow: hidden;">
          <TxScroll style="height: 100%;" :bounce="true" :scroll-chaining="true">
            <div style="height: 520px; display: flex; flex-direction: column; gap: 8px;">
              <div class="demo-scroll-item">
                Inner (opt-in): scrollChaining = true
              </div>
              <div v-for="i in 18" :key="i" class="demo-scroll-item">
                Item {{ i }}
              </div>
            </div>
          </TxScroll>
        </div>

        <div class="demo-scroll-item">
          Outer scroll area (bottom)
        </div>
      </div>
    </div>
  </div>
</template>

使用原生滚动

当你不需要 BetterScroll 行为时,可以切换为原生滚动(仍保持统一容器结构)。

Scroll (native)

示例即将加载...
<template>
  <div class="demo-container" style="height: 220px;">
    <div style="height: 100%;">
      <TxScroll native style="height: 100%;">
        <div style="height: 1200px; display: flex; flex-direction: column; gap: 8px;">
          <div v-for="i in 60" :key="i" class="demo-scroll-item">
            Native Row {{ i }}
          </div>
        </div>
      </TxScroll>
    </div>
  </div>
</template>

下拉刷新与上拉加载

  • 下拉刷新:设置 pullDownRefresh,监听 @pulling-down,完成后调用 finishPullDown()
  • 上拉加载:设置 pullUpLoad,监听 @pulling-up,完成后调用 finishPullUp()
  • native=true 或自动原生回退时,事件为降级触发;pullDownStop 仅 BetterScroll 模式生效。

Scroll (pull down + pull up)

示例即将加载...
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(Array.from({ length: 30 }, (_, i) => i + 1))
const scrollRef = ref<any>(null)
const loading = ref(false)

function sleep(ms: number) {
  return new Promise<void>(resolve => setTimeout(resolve, ms))
}

async function onPullingDown() {
  loading.value = true
  await sleep(600)
  items.value = Array.from({ length: 30 }, (_, i) => i + 1)
  loading.value = false
  scrollRef.value?.finishPullDown?.()
}

async function onPullingUp() {
  if (loading.value)
    return
  loading.value = true
  await sleep(600)
  const last = items.value[items.value.length - 1] ?? 0
  items.value.push(...Array.from({ length: 20 }, (_, i) => last + i + 1))
  loading.value = false
  scrollRef.value?.finishPullUp?.()
}
</script>

<template>
  <div class="demo-container" style="height: 260px;">
    <TxScroll
      ref="scrollRef"
      style="height: 100%;"
      :pull-down-refresh="true"
      :pull-up-load="true"
      @pulling-down="onPullingDown"
      @pulling-up="onPullingUp"
    >
      <div style="display: flex; flex-direction: column; gap: 8px;">
        <div v-for="i in items" :key="i" class="demo-scroll-item">
          Item {{ i }}
        </div>
      </div>

      <template #footer>
        <div style="padding: 10px 0; color: var(--tx-text-color-secondary); text-align: center;">
          {{ loading ? 'Loading...' : 'Pull up to load more' }}
        </div>
      </template>
    </TxScroll>
  </div>
</template>

API

Props

属性名类型默认值说明
nativebooleanfalse使用原生滚动
unifiedbooleanfalse强制由 BetterScroll 接管滚动(跨环境统一行为,会覆盖 Safari/Chromium 自动原生;native=true 仍优先生效)
nativeAutoFallbackbooleantrue控制 macOS + Chromium 145+ 自动回退原生滚动;不影响 macOS Safari 的原生优先策略
noPaddingbooleanfalse禁用内边距
scrollChainingbooleanfalse是否允许滚动链(到边界后继续带动父级滚动);不建议默认开启,仅在明确需要父子联动时启用
direction'vertical' | 'horizontal' | 'both''vertical'滚动方向
scrollbarbooleantrue是否启用 BetterScroll 滚动条
scrollbarFadebooleantrue滚动条自动淡出
scrollbarInteractivebooleantrue滚动条是否可拖拽
scrollbarAlwaysVisiblebooleanfalse强制滚动条常显(用于 bounce/无边界场景)
scrollbarMinSizenumber18指示器最小尺寸(px)
probeType0 | 1 | 2 | 33BetterScroll probeType
bouncebooleantrue是否开启边界回弹
clickbooleantrue是否派发 click(BetterScroll 选项)
wheelbooleantrue是否拦截滚轮并驱动 BetterScroll
refreshOnContentChangebooleantrue内容变更时自动 refresh
pullDownRefreshboolean | Record<string, unknown>false下拉刷新(BetterScroll 模式为原生能力;native 模式为降级触发)
pullDownThresholdnumber70下拉触发阈值(px)
pullDownStopnumber56下拉停留距离(px,仅 BetterScroll)
pullUpLoadboolean | Record<string, unknown>false上拉加载更多(BetterScroll 模式为原生能力;native 模式为降级触发)
pullUpThresholdnumber0距离底部阈值(px)
optionsRecord<string, unknown>{}BetterScroll 初始化参数(兜底,会覆盖部分默认值)

Events

事件名参数说明
scroll{ scrollTop: number; scrollLeft: number }滚动事件
pulling-down-触发下拉刷新
pulling-up-触发上拉加载更多