better-scroll的用法
//结构
<div class="wrapper">
<ul class="content">
<li>...</li>
<li>...</li>
...
</ul>
</div>
//js
import BScroll from 'better-scroll';
let wrap=document.querySelector('#wrapper');
let scroll =new BScroll(wrap,{})
原理
- wrapper中只有第一个元素content可以滚动
- 在初始化的时候,会计算父元素和子元素的高度和宽度,来决定是否可以纵向和横向滚动。因此,我们在初始化它的时候,必须确保父元素和子元素的内容已经正确渲染了。如果子元素或者父元素 DOM 结构发生改变的时候,必须重新调用 scroll.refresh() 方法重新计算来确保滚动效果的正常。
vue中使用better-scroll
<template>
<div class="wrapper" ref='wrapper'>
<ul class="content">
<li>...</li>
<li>...</li>
...
</ul>
</div>
</template>
<script>
import BScroll from 'better-scroll'
export default {
mounted(){
this.$nextTick(() => {
this.scroll = new Bscroll(this.$refs.wrapper, {})
})
}
}
</script>
实现下拉刷新,上拉加载更多的需求
<template>
<div ref='wrapper'>
<ul class="content">
<li v-for="item in data">{{item}}</li>
</ul>
<div class="loading-wrapper"></div>
</div>
</template>
<script>
new Vue({
el:'#app',
template:'#wrapper',
data:{
data:[1,2,3,4,5,6,7,8,9,0,2,1,3,4,5,6,7,8],
dropDown:false
},
created() {
this.loadData();
},
methods: {
loadData() {
//getData().then((res) => {
this.data = this.data.concat(this.data)
this.$nextTick(() => {
if (!this.scroll) {
this.scroll = new BScroll(this.$refs.wrapper, {})
this.scroll.on('scroll', (pos) => {
//如果下拉超过50px 就显示下拉刷新的文字
if(pos.y>50){
this.dropDown = true
}else{
this.dropDown = false
}
})
this.scroll.on('touchEnd', (pos) => {
// 下拉动作
if(pos.y > 50){
console.log("下拉刷新成功")
this.dropDown = false
}
//上拉加载 总高度>下拉的高度+10 触发加载更多
if(this.scroll.maxScrollY>pos.y+10){
console.log("加载更多")
//使用refresh 方法 来更新scroll 解决无法滚动的问题
this.loadData()
this.scroll.refresh()
}
})
} else {
this.scroll.refresh()
}
})
//})
}
}
})
</script>
封装better-scroll组件
上边的代码实现了基本的功能,但是每次使用的时候都需要写入这么多的代码,所以我将他封装成一个组件scroll
<template>
<div ref="wrapper">
<slot></slot><!--分发内容-->
</div>
</template>
<script>
import BScroll from 'better-scroll'
export default {
props: {
/**
* 1 滚动的时候会派发scroll事件,会截流。
* 2 滚动的时候实时派发scroll事件,不会截流。
* 3 除了实时派发scroll事件,在swipe的情况下仍然能实时派发scroll事件
*/
probeType: {
type: Number,
default: 1
},
/**
* 点击列表是否派发click事件
*/
click: {
type: Boolean,
default: true
},
/**
* 是否开启横向滚动
*/
scrollX: {
type: Boolean,
default: false
},
/**
* 是否派发滚动事件
*/
listenScroll: {
type: Boolean,
default: false
},
/**
* 列表的数据
*/
data: {
type: Array,
default: null
},
/**
* 是否派发滚动到底部的事件,用于上拉加载
*/
pullup: {
type: Boolean,
default: false
},
/**
* 是否派发顶部下拉的事件,用于下拉刷新
*/
pulldown: {
type: Boolean,
default: false
},
/**
* 是否派发列表滚动开始的事件
*/
beforeScroll: {
type: Boolean,
default: false
},
/**
* 当数据更新后,刷新scroll的延时。
*/
refreshDelay: {
type: Number,
default: 20
}
},
mounted() {
// 保证在DOM渲染完毕后初始化better-scroll
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,
scrollX: this.scrollX
})
//父组件可以通过@setScroll方法拿到scroll实例,进行配置
this.$emit('setScroll',this.scroll);
// 是否派发滚动事件
if (this.listenScroll) {
this.scroll.on('scroll', (pos) => {
this.$emit('scroll', pos)
})
}
// 是否派发滚动到底部事件,用于上拉加载
if (this.pullup) {
this.scroll.on('scrollEnd', () => {
// 滚动到底部
if (this.scroll.y <= (this.scroll.maxScrollY + 50)) {
this.$emit('scrollToEnd')
}
})
}
// 是否派发顶部下拉事件,用于下拉刷新
if (this.pulldown) {
this.scroll.on('scrollEnd', (pos) => {
// 下拉动作
if (pos.y > 50) {
this.$emit('pulldown')
}
})
}
// 是否派发列表滚动开始的事件
if (this.beforeScroll) {
this.scroll.on('beforeScrollStart', () => {
this.$emit('beforeScroll')
})
}
},
//父组件可以通过this.@refs拿到组件 并调用组件上的这些方法
disable() {
// 代理better-scroll的disable方法
this.scroll && this.scroll.disable()
},
enable() {
// 代理better-scroll的enable方法
this.scroll && this.scroll.enable()
},
refresh() {
// 代理better-scroll的refresh方法
this.scroll && this.scroll.refresh()
},
scrollTo() {
// 代理better-scroll的scrollTo方法
this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
},
scrollToElement() {
// 代理better-scroll的scrollToElement方法
this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
}
},
watch: {
// 监听数据的变化,延时refreshDelay时间后调用refresh方法重新计算,保证滚动效果正常
data() {
setTimeout(() => {
this.refresh()
}, this.refreshDelay)
}
}
}
</script>
使用这个组件
<template>
<scroll class="wrapper"
:data="data"
:pulldown="pulldown"
@setScroll="setScroll"
@pulldown="loadData"
ref="scro">
<ul class="content">
<li v-for="item in data">{{item}}</li>
</ul>
<div class="loading-wrapper"></div>
</scroll>
</template>
<script>
import BScroll from 'better-scroll'
export default {
data() {
return {
data: [],
pulldown: true
}
},
created() {
this.loadData()
},
mounted(){
this.$nextTick(()=>{
this.$refs.scro.scrollToElement('dom');
})
},
methods: {
loadData() {
requestData().then((res) => {
this.data = res.data.concat(this.data)
})
},
setScroll(scroll){
this.scroll = scroll;
console.log("scroll创建成功");
},
}
}
</script>
better-scroll作为指令封装
未完待续