开发页面时,如果想让某个区域支持滚动(或者需要监听滚动事件),一般会使用better-scroll——一款重点解决移动端(已支持 PC)各种滚动场景需求的插件,作者依然是黄轶老师,具体使用方法和例子可查看官方文档。
学习《Vue.js高仿饿了么 》 时第一次接触better-scroll ,在使用该插件的过程中,发现实现步骤、逻辑基本一致,如果能固化这些步骤抽象成自定义组件( scroll.vue,类似于微信小程序的scroll-view组件 ),日后再有类似的滚动需求,直接调用<scroll></scroll>
即可,这样也使代码更简洁高效且易于维护。
首先需要安装better-scroll,执行命令:cnpm i better-scroll -S
一、 src/base/scroll/scroll.vue
<template>
<!--这部分的代码很简单(模板代码越简单说明组件使用越灵活),最外层是一个包裹层,中间一个插槽slot,意味着将来需要滚动的元素会放在该插槽的位置,值得注意的是,对于插入slot的多个子元素,只有第一个子元素可以滚动-->
<div ref="wrapper">
<slot></slot>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from 'better-scroll'
export default {
name: 'scroll',
props: {
// 有时候我们需要知道滚动的位置。
// 1:会非实时(屏幕滑动超过一定时间后)派发scroll事件;2:会在屏幕滑动的过程中实时的派发scroll事件;3:不仅在屏幕滑动的过程中,而且在momentum滚动动画运行过程中实时派发scroll事件;不设置则默认为0,即不派发scroll事件。
probeType: {
type: Number,
default: 1
},
// 是否手动派发点击事件,better-scroll默认会阻止浏览器的原生click事件。
// true:better-scroll会派发一个click事件。
click: {
type: Boolean,
default: true
},
// 是否监听滚动
listenScroll: {
type: Boolean,
default: false
},
// 用于滚动的列表数据
data: {
type: Array,
default: null
},
// 滚动前的钩子
beforeScroll: {
type: Boolean,
default: false
},
// 刷新前的延迟时间,单位:毫秒
refreshDelay: {
type: Number,
default: 20
}
},
// 在mounted钩子中初始化scroll
mounted () {
// 延迟20毫秒是用于抵消浏览器的刷新耗时(一般17毫秒),确保DOM已经渲染
setTimeout(() => {
this._initScroll()
}, 20)
},
methods: {
_initScroll () {
if (!this.$refs.wrapper) {
return
}
// 初始化better-scroll
this.scroll = new BScroll(this.$refs.wrapper, {
probeType: this.probeType,
click: this.click
})
// 如果需要监听滚动,则向上派发scroll事件
if (this.listenScroll) {
let that = this
this.scroll.on('scroll', (pos) => {
that.$emit('scroll', pos)
})
}
if (this.beforeScroll) {
this.scroll.on('beforeScrollStart', () => {
this.$emit('beforeScroll')
})
}
},
// 以下是对一些better-scroll方法的代理
disable () {
this.scroll && this.scroll.disable()
},
enable () {
this.scroll && this.scroll.enable()
},
refresh () {
this.scroll && this.scroll.refresh()
},
scrollTo () {
this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
},
scrollToElement () {
this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
}
},
// 设置一个监听器,如果data发生变化,就需要重新计算scroll的高度,即调用refresh()方法
watch: {
data () {
setTimeout(() => {
this.refresh()
}, this.refreshDelay)
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
</style>
二、使用方法
<scroll :data="list" :listen-scroll="true" @scroll="scroll">
<!--只要第一个元素才会滚动-->
<ul>
<li v-for="item in list">
...
</li>
</ul>
<!--以下元素不会滚动-->
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
</scroll>
三、常见问题及处理
- 如果better-scroll不能滚动,可能是因为滚动元素的DOM未渲染成功,better-scroll计算不了滚动元素的高度,从而失效;
- 如果滚动数据或DOM发生变化,一定要执行better-scroll的refresh;
- 当better-scroll和fastclick在点击事件上有冲突,可以为目标元素添加fastclick提供的“needsclick”样式类解决。
1+
0 条评论