vue3+betterScroll scroll滚动组件

betterScroll在MVVM框架中使用时最麻烦的是更新时机,一般的需要滚动的列表数据都是来源于后端,是异步的。就必须要渲染完后refresh()一下。但是单独的Scroll组件是通过插槽放置列表数据内容的,无法直接确定什么时候更新了节点。通过插槽放置内容,当内容加载完成就更新betterScroll实例,这里就涉及到父子传递,这里使用了依赖注入的办法把refresh()传递到子组件中

新建一个page.vue组件 betterScroll需要的基本结构
点击查看代码
<!-- page.vue -->
<template>
  <div class="page">
    <div class="center">
      <slot></slot>
    </div>
  </div>
</template>

<script setup lang='ts'>

</script>
<style lang="less" >
.page {
  width: 100%;
  height: 100%;
  min-width: fit-content;
  max-width: 100vw;
  overflow: hidden;

  .center {
    height: auto;
  }
}
</style>

新建use-scroll.ts

scrollRef是要监听滚动的DOM 在这里声明后把它传出到组件绑定到ref
bs放置BScroll实例
在getScroll方法中new BScroll,如果已经new过了就直接更新原来的bs实例
更新时需要在等待DOM更新完成也就是放在nextTick之后

//use-scroll.ts
import type { Options } from '@better-scroll/core';
import BScroll from '@better-scroll/core';
import MouseWheel from '@better-scroll/mouse-wheel';
import ScrollBar from '@better-scroll/scroll-bar';
import { nextTick, onMounted, onUnmounted, ref } from 'vue';

BScroll.use(MouseWheel)//鼠标滚轮
BScroll.use(ScrollBar)//滚动条

/**
 * BScroll 滚动
 * @param { Options } options BScroll配置项
 * @returns { {scrollRef,bs,getScroll} }
 */
export default (options?: Options) => {
  const scrollRef = ref<HTMLElement>()
  const bs = ref<BScroll | undefined>()

  //new BScroll 如果new过了就直接更新
  const getScroll = async () => {
    if (!scrollRef.value) return
    if (!bs.value) {
      // BetterScroll实例
      bs.value = new BScroll(scrollRef.value, {
        scrollY: true,//沿Y轴滚动
        scrollX: true,//沿X轴滚动
        click: true,//派发点击事件
        probeType: 3,//反向偏移量
        mouseWheel: true,//开启鼠标滚轮插件
        scrollbar: true,//开启滚动条插件
        ...(options || {})
      })
      return
    }
    await nextTick()
    bs.value.refresh()//更新BScroll
  }

  onMounted(() => {
    getScroll()
  })

  onUnmounted(() => {
    // 移除BetterScroll
    bs.value && bs.value.destroy && bs.value.destroy?.()
  })

  return {
    scrollRef,//所监听的ref
    bs, //BetterScroll实例
    getScroll,//重新计算scroll
  }
}

修改page.vue组件

引入use-scroll.ts 把scrollRef绑定到外层节点上
添加依赖注入 把getScroll提供给子组件 provide('scroll', getScroll)

<template>
  <div class="page" ref="scrollRef">
    <div class="center">
      <slot></slot>
    </div>
  </div>
</template>

<script setup lang='ts'>
import scroll from './use-scroll';
const { scrollRef, getScroll, bs } = scroll()//使用BetterScroll
// 注入更新BScroll方法 子组件在节点变化后调用
provide('scroll', getScroll)

</script>
<style lang="less" >
.page {
  width: 100%;
  height: 100%;
  min-width: fit-content;
  max-width: 100vw;
  overflow: hidden;

  .center {
    height: auto;
  }
}
</style>

新建一个list.vue 渲染20张图片列表

<template>
  <ul>
    <li v-for="item in data.list">
      <img style="width:100%" :src="item.img" alt="">
    </li>
  </ul>
</template>

<script setup lang='ts'>
import { onMounted, reactive } from 'vue';
const getScroll = inject<Function>('scroll', () => { })//接收getScroll
const data = reactive<{ list: { img: string }[] }>({
  list: []
})

onMounted(() => {
  // 5秒后更新数据并调用getScroll重新计算
  setTimeout(() => {
    data.list = Array(20).fill({ img: 'data:image/jpeg;base64,/9j/.....' })//20张图片
    getScroll()
  }, 5000)
})
</script>

引入到App.vue中使用

<script setup lang="ts">
import list from './views/pages/list.vue';
import page from './components/pageView/page.vue';
</script>

<template>
  <page class="main">
    <list />
  </page>
</template>

<style scoped>
.main {
  width: 100vw;
  height: 100vh;
}
</style>

最终效果

image

posted @   真是要好  阅读(1147)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示