目录
- npm install @better-scroll/core --save
-
- // or
-
- yarn add @better-scroll/core
- npm install @better-scroll/slide --save
-
- // or
-
- yarn add @better-scroll/slide
这样就表示我们安装完成:

在 components 目录下新建 slide/slide.vue 来编写轮播图相关代码


下面是 slide.vue 的代码:
- <template>
- <div class="slider" ref="rootRef">
- <div class="slider-group">
- <div
- class="slider-page"
- v-for="item in sliders"
- :key="item.id"
- >
- <img :src="item.pic"/>
- div>
- div>
- <div class="dots-wrapper">
- <span
- class="dot"
- v-for="(item, index) in sliders"
- :key="item.id"
- :class="{'active': currentPageIndex === index}">
- span>
- div>
- div>
- template>
-
- <script>
- import BScroll from '@better-scroll/core'
- import Slide from '@better-scroll/slide'
-
- import { onMounted, onUnmounted, onActivated, onDeactivated, ref } from 'vue'
-
- BScroll.use(Slide)
-
- export default {
- name: 'slider',
- props: {
- sliders: {
- type: Array,
- default() {
- return []
- }
- }
- },
- setup(props) {
- const rootRef = ref(null)
- const slider = ref(null)
- const currentPageIndex = ref(0)
- onMounted(() => {
- const sliderVal = slider.value = new BScroll(rootRef.value, {
- click: true,
- scrollX: true,
- scrollY: false,
- momentum: false,
- bounce: false,
- probeType: 2,
- slide: true
- })
- sliderVal.on('slideWillChange', (page) => {
- currentPageIndex.value = page.pageX
- })
- })
- onUnmounted(() => {
- slider.value.destroy()
- })
-
- onActivated(() => {
- slider.value.enable()
- slider.value.refresh()
- })
-
- onDeactivated(() => {
- slider.value.disable()
- })
-
- return {
- slider,
- currentPageIndex,
- rootRef
- }
- }
- }
- script>
-
- <style lang="less" scoped>
- .slider {
- position :relative;
- .slider-group {
- position: relative;
- overflow: hidden;
- white-space: nowrap;
- .slider-page {
- display: inline-block;
- transform: translate3d(0, 0, 0);
- backface-visibility: hidden;
- a {
- display: block;
- width: 100%;
- }
- img {
- display: block;
- width: 100%;
- }
- }
- }
- .dots-wrapper {
- position: absolute;
- left: 50%;
- bottom: 12px;
- line-height: 12px;
- transform: translateX(-50%);
- .dot {
- display: inline-block;
- margin: 0 4px;
- width: 8px;
- height: 8px;
- border-radius: 50%;
- background: rgba(255, 255, 255, 0.5);
- &.active {
- width: 20px;
- border-radius: 5px;
- background:rgba(255, 255, 255, 0.8);
- }
- }
- }
- }
- style>
轮播的信息通过 props 从父组件传递过来,下面是父组件的代码:
- <template>
- <header>头部header>
- <div>
- <slide :sliders="list">slide>
- div>
- template>
-
- <script>
- import slide from '../components/slider/slider.vue'
- import { ref } from 'vue'
- export default {
- name: 'HomeView',
- components: {
- slide
- },
- setup () {
- const list = ref([
- {
- id: 1,
- pic: "https://7463-tcb-tjpv7cz5f6ef80-7dw7b0630091b-1312294860.tcb.qcloud.la/swiper/havetea.png"
- },
- {
- id: 2,
- pic: "https://7463-tcb-tjpv7cz5f6ef80-7dw7b0630091b-1312294860.tcb.qcloud.la/swiper/谨防诈骗.png"
- },
- {
- id: 3,
- pic: "https://7463-tcb-tjpv7cz5f6ef80-7dw7b0630091b-1312294860.tcb.qcloud.la/swiper/首页轮播1.png"
- }
- ])
- return {
- list
- }
- },
- }
- script>
- <style lang="less" scoped>
- header {
- height: 30px;
- width: 100%;
- background-color: pink;
- }
- style>
启动项目,看一下我们的轮播图:

下面我们再使用 composition api 的方式创建一个钩子函数,把 new slide 的逻辑抽离出去:

我们定义了一个 useSlider 函数,他传入的参数是轮播图的容器,这个是 betterScroll 必须的,返回的是当前页的索引值,下面我们看一下 use-slider.js 的代码:
- import { onMounted, onUnmounted, onActivated, onDeactivated, ref } from 'vue'
- import BScroll from '@better-scroll/core'
- import Slide from '@better-scroll/slide'
- BScroll.use(Slide)
- export default function useSlider(wrapperRef) {
- const slider = ref(null)
- const currentPageIndex = ref(0)
- onMounted(() => {
- const sliderVal = slider.value = new BScroll(wrapperRef.value, {
- click: true,
- scrollX: true,
- scrollY: false,
- momentum: false,
- bounce: false,
- probeType: 2,
- slide: true
- })
- sliderVal.on('slideWillChange', (page) => {
- currentPageIndex.value = page.pageX
- })
- })
- onUnmounted(() => {
- slider.value.destroy()
- })
-
- onActivated(() => {
- slider.value.enable()
- slider.value.refresh()
- })
-
- onDeactivated(() => {
- slider.value.disable()
- })
- return {
- slider,
- currentPageIndex
- }
- }
然后再看一下现在 slider.vue 的代码,就会感受到 composition api 的强大之处了:
- import { ref } from 'vue'
- import useSlider from './use-slider'
- export default {
- name: 'slider',
- props: {
- sliders: {
- type: Array,
- default() {
- return []
- }
- }
- },
- setup() {
- const rootRef = ref(null)
- const { currentPageIndex } = useSlider(rootRef)
- return {
- rootRef,
- currentPageIndex
- }
- }
- }
这样处理之后,useSlider 函数只跟 slide 轮播图的创建有关,主逻辑部分很清晰。
在我们移动端的开发中经常会遇到滚动列表的场景,此时我们用原生的滚动效果是没有回弹及一些其他对交互很友好的动画效果的,类似于这样:

同样借助于 BetterScroll 我们可以轻松的封装一个自己的滚动组件来实现移动端下顺滑的滚动体验
在 components 目录下新建 scroll / scroll.vue 文件,它的实现非常简单:
- <div ref="rootRef">
- <slot>slot>
- div>
-
- <script>
-
- export default {
- name: 'scroll'
- }
- script>
滚动的内容部分我们就放在 slot 插槽中,然后在外层的 div 盒子中通过 BetterScroll 做一些初始化的联动,让内容部分实现滚动。
和上一讲的 slider 组件一样,我们使用 composition api 和 钩子函数的方式来和 BetterScroll 做初始化,所以我们新建 use-scroll.js 文件,代码如下所示
- import BScroll from '@better-scroll/core'
- import { onMounted, onUnmounted, ref } from 'vue'
-
- BScroll.use(ObserveDOM)
-
- export default function useScroll(wrapperRef) {
- const scroll = ref(null)
-
- onMounted(() => {
- scroll.value = new BScroll(wrapperRef.value)
-
- onUnmounted(() => {
- scroll.value.destroy()
- })
-
- }
这里的 wrapperRef 就是最外层的 dom ,我们通过 ref 获取他然后作为参数传进来,下一步我们在 scroll 中引入这个钩子函数:
- <div ref="rootRef">
- <slot>slot>
- div>
-
- <script>
- import useScroll from './use-scroll'
- import { ref } from 'vue'
-
- export default {
- name: 'scroll',
- setup() {
- const rootRef = ref(null)
- const scroll = useScroll(rootRef)
- return {
- rootRef
- }
- }
- }
- script>
这样我们简单的 scroll 组件就实现了
因为 BetterScroll 是支持我们添加很多自定义属性和事件的,比如在官网中可以定义 click 点击事件,它的默认值是 false:

现在我们就给我们的滚动组件添加这个 click 事件,这里的 click 我们想实现自定义配置就应该从使用 scroll 组件的父级传进来,那我们通过 props 接收他就好,然后把 props 作为参数传给需要用到他的钩子函数,这样不论 props 中添加了什么新的属性,钩子函数中都能获取到,因为都包含在 props 中,修改 scroll.vue 代码如下:
- <div ref="rootRef">
- <slot>slot>
- div>
-
- <script>
- import useScroll from './use-scroll'
- import { ref } from 'vue'
-
- export default {
- name: 'scroll',
- props: {
- click: {
- type: Boolean,
- default: true
- }
- setup(props) {
- const rootRef = ref(null)
- useScroll(rootRef, props, emit)
-
- return {
- rootRef
- }
- }
- }
- script>
值得注意的是, scroll 组件只对第一个子节点生效,这也是 BeterScroll 的特性。
如果 BetterScroll 的时候,并没有实现滚动,可以看一下文档中的滚动原理:

BetterScroll 判断滚动是在初始化的时候就进行判断,也就是在 new BScroll 的时候进行计算,如果我们在 created 的时候获取列表数据,那显然很有可能我们在数据还没有获取的时候,BetterScroll 已经计算完了,这样页面就滚动不了。
解决这个问题的方法就是 BetterScroll 的一个插件:observe-dom:

这样当 我们的 dom 发生变化时,BetterScroll就能自动感知然后执行刷新操作。
- npm install @better-scroll/observe-dom --save
-
- // or
-
- yarn add @better-scroll/observe-dom
use-scroll.vue:
- import BScroll from '@better-scroll/core'
- import ObserveDOM from '@better-scroll/observe-dom'
- import { onMounted, onUnmounted, ref } from 'vue'
-
- BScroll.use(ObserveDOM)
-
- export default function useScroll(wrapperRef, options) {
- const scroll = ref(null)
-
- onMounted(() => {
- scroll.value = new BScroll(wrapperRef.value, {
- observeDOM: true,
- ...options
- })
-
- onUnmounted(() => {
- scroll.value.destroy()
- })
- }
我们试一下使用 scroll.vue 组件后的滚动列表的效果,下面是 Home.vue 的代码:
- <template>
- <div style="position:relative;">
- <div class="head">固定的头部div>
- <div class="main">
- <scroll class="theScroll">
- <div>
- <div v-for="(i,index) in 10" :key="index" style="margin:10px 0">
- <van-card
- num="2"
- price="2.00"
- desc="描述信息"
- title="商品标题"
- thumb="https://fastly.jsdelivr.net/npm/@vant/assets/ipad.jpeg"
- />
- div>
- div>
- scroll>
- div>
- div>
- template>
-
- <script>
- import slide from '../components/slider/slider.vue'
- import scroll from '../components/scroll/scroll.vue'
- import { ref } from 'vue'
- export default {
- name: 'HomeView',
- components: {
- slide,
- scroll
- },
- setup () {
- const list = ref([
- {
- id: 1,
- pic: "https://7463-tcb-tjpv7cz5f6ef80-7dw7b0630091b-1312294860.tcb.qcloud.la/swiper/havetea.png"
- },
- {
- id: 2,
- pic: "https://7463-tcb-tjpv7cz5f6ef80-7dw7b0630091b-1312294860.tcb.qcloud.la/swiper/谨防诈骗.png"
- },
- {
- id: 3,
- pic: "https://7463-tcb-tjpv7cz5f6ef80-7dw7b0630091b-1312294860.tcb.qcloud.la/swiper/首页轮播1.png"
- }
- ])
- return {
- list
- }
- },
- }
- script>
- <style lang="less" scoped>
- .head {
- position: fixed;
- top: 0;
- left: 0;
- height: 50px;
- width: 100%;
- background-color: pink;
- z-index: 999;
- }
- .main {
- position: fixed;
- top: 50px;
- bottom: 0;
- left: 0;
- right: 0;
- background-color: rgb(232, 234, 235);
- .theScroll {
- height: 100%;
- overflow: hidden;
- }
- }
- style>
启动项目,查看效果:

现在我们就实现了带回弹效果的这样顺滑的滚动了。