某一个页面的列表使用better-scroll的上拉加载和下拉刷新功能,better-scroll被封装成vue的组件
1。页面中
<my-scroll
ref="myScroll"
:startY="parseInt(startY)"
:listArr="state.testList" // 列表数据
:haveDataFlag="state.listHaveDataFlag" //分页请求,下一页是否有数据的标识
:pullup="pullupFlag" // 是否开启上拉加载
@scrollEnd="onLoadFun" // 上拉加载的方法
:pullDownRefresh="pullDownRefreshObj" // 是否派发下拉刷新
@pullingDown="onPullingDown" //下拉刷新的方法
>
<test-list></test-list> //列表
</my-scroll>
data() {
return {
pullDownRefresh: true,
startY: 0,
pullDownRefreshThreshold: 90,
pullDownRefreshStop: 40,
pullupFlag: true, // 上拉加载
};
},
computed:{
pullDownRefreshObj() {
return this.pullDownRefresh
? {
threshold: parseInt(this.pullDownRefreshThreshold),
stop: parseInt(this.pullDownRefreshStop)
}
: false;
}
}
methods:{
// 上拉加载
async onLoadFun() {
await this.updateInfo({
pageNum: this.state.pageNum+ 1
});
if (this.state.nextTestList.length === 0) {
// 如果下一页没有数据,停止上拉加载
this.pullupFlag = false;
return;
}
// 请求接口
await this.listRequest();
},
// 下拉刷新
async onPullingDown() {
//打印this可以看到_isDestroyed,当前实例是否已经被销毁
if (this._isDestroyed) return;
await this.updateInfo({
stockMarketPageNum: 1, // 行情列表分页
stockMarketList: [], // 行情列表
nextStockMarketList: [] //行情新请求列表
});
this.listRequest();
},
// 重新初始化组件
rebuildScroll() {
Vue.nextTick(() => {
this.$refs.myScroll.destroy();
this.$refs.myScroll.initScroll();
});
},
},
watch: {
startY(nval,oval) {
this.rebuildScroll();
}
},
- 组件中
<template>
<div class="my-scroll" ref="myScroll">
<div class="scroll-content">
<slot></slot>
<div class="pull-up-box" v-if="fatherNeedPullFlag">
<img
v-show="isPullUp"
src="@/assets/img/loading_01.gif"
alt
style="width:0.2rem;height0.2rem;"
/>
<div :class="listArr.length > 0 ? 'have-data':'no-data'">
<span v-show="haveDataFlag">没有更多数据了</span>
</div>
</div>
</div>
<slot
name="pulldown"
:pullDownRefresh="pullDownRefresh"
:pullDownStyle="pullDownStyle"
:beforePullDown="beforePullDown"
:isPullingDown="isPullingDown"
>
<div ref="pulldown" class="pulldown-wrapper" :style="pullDownStyle" v-if="pullDownRefresh">
<div class="before-trigger" v-if="beforePullDown"></div>
<div class="after-trigger" v-else>
<div v-if="isPullingDown" class="loading">
<img style="width:0.3rem;height:0.3rem;" src="@/assets/img/loading_01.gif" />
</div>
<div v-else>
<p class="refresh-txt">{{ refreshTxt }}</p>
</div>
</div>
</div>
</slot>
</div>
</template>
<script type="text/ecmascript-6">
import BScroll from "better-scroll";
export default {
name: "myScroll",
data() {
return {
beforePullDown: true,
pullDownStyle: "",
isPullingDown: false,
isRebounding: false
};
},
props: {
scrollFun: {
type: Function,
default: function() {
return f => f;
}
},
/**
* 1 滚动的时候会派发scroll事件,会截流。
* 2 滚动的时候实时派发scroll事件,不会截流。
* 3 除了实时派发scroll事件,在惯性或动画的情况下仍然能实时派发scroll事件
*/
probeType: {
type: Number,
default: 1
},
/**
* 点击列表是否派发click事件
*/
click: {
type: Boolean,
default: true
},
/**
* 是否开启横向滚动
*/
scrollX: {
type: Boolean,
default: false
},
/**
* 是否派发滚动事件
*/
listenScroll: {
type: Boolean,
default: false
},
/**
* 列表的数据
*/
listArr: {
type: Array,
default: null
},
/**
* 是否派发滚动到底部的事件,用于上拉加载
*/
pullup: {
type: Boolean,
default: false
},
/**
* 是否派发顶部下拉的事件,用于下拉刷新
*/
pullDownRefresh: {
type: null,
default: false
},
/**
* 是否派发列表滚动开始的事件
*/
beforeScroll: {
type: Boolean,
default: false
},
/**
* 当数据更新后,刷新scroll的延时。
*/
refreshDelay: {
type: Number,
default: 20
},
bounce: {
// 当滚动超过边缘的时候会有一小段回弹动画
type: Boolean,
default: true
},
fatherNeedPullFlag: {
// 是否展示底部加载动画和文字
type: Boolean,
default: true
},
// nextListArr: { // 下次请求的新数据
// type:Array,
// default:[]
// },
isPullUp: {
type: Boolean,
default: false
},
haveDataFlag: {
type: Boolean,
default: false
}
},
created() {
this.pullDownInitTop = -40;
},
computed: {
refreshTxt() {
return (this.pullDownRefresh && this.pullDownRefresh.txt) || "刷新成功";
}
},
mounted() {
this.$nextTick(() => {
this._initScroll();
});
},
destroyed() {
this.$refs.myScroll && this.$refs.myScroll.destroy();
},
methods: {
_initScroll() {
if (!this.$refs.myScroll) {
return;
}
let options = {
probeType: this.probeType,
scrollX: this.scrollX,
bounce: this.bounce, // 回弹动画
pullup: this.pullup,
pullDownRefresh: this.pullDownRefresh,
taps: true,
click: true
};
// better-scroll的初始化
this.scroll = new BScroll(this.$refs.myScroll, options);
// 是否派发滚动事件
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("scrollEnd");
}
});
}
// 监听滚动高度
if (this.scrollFun) {
this.scroll.on("scroll", scrollValue => {
// 滚动到底部
// console.log(scrollValue.y)
this.$emit("scrollFun", scrollValue);
});
}
// 是否派发顶部下拉事件,用于下拉刷新
if (this.pullDownRefresh) {
this._initPullDownRefresh();
}
// 是否派发列表滚动开始的事件
if (this.beforeScroll) {
this.scroll.on("beforeScrollStart", () => {
this.$emit("beforeScroll");
});
}
},
forceUpdate() {
if (this.pullDownRefresh && this.isPullingDown) {
this.isPullingDown = false;
this._reboundPullDown().then(() => {
this._afterPullDown();
});
}
if (this.pullup && this.isPullUp) {
this.isPullUp = false;
this.scroll.finishPullUp();
this.refresh();
} else {
this.refresh();
}
},
_afterPullDown() {
setTimeout(() => {
this.pullDownStyle = `top:${this.pullDownInitTop}px`;
this.beforePullDown = true;
this.isRebounding = false;
this.refresh();
}, this.scroll.options.bounceTime);
},
_initPullDownRefresh() {
this.scroll.on("pullingDown", () => {
this.beforePullDown = false;
this.isPullingDown = true;
this.$emit("pullingDown");
});
this.scroll.on("scroll", pos => {
if (!this.pullDownRefresh) {
return;
}
if (this.beforePullDown) {
this.pullDownStyle = `top:${Math.min(
pos.y + this.pullDownInitTop,
0
)}px`;
}
if (this.isRebounding) {
this.pullDownStyle = `top:${0 -
(this.pullDownRefresh.stop - pos.y)}px`;
}
});
},
_reboundPullDown() {
const { stopTime = 300 } = this.pullDownRefresh;
return new Promise(resolve => {
setTimeout(() => {
this.isRebounding = true;
this.scroll.finishPullDown();
resolve();
}, stopTime);
});
},
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);
},
destroy() {
this.scroll.destroy();
}
},
watch: {
// 监听数据的变化,延时refreshDelay时间后调用refresh方法重新计算,保证滚动效果正常,如果是下拉刷新,时间稍微调整长点
listArr(nVal, oVal) {
let times = 800;
if (this.isPullingDown) {
times = 800;
} else {
times = 30;
}
setTimeout(() => {
this.refresh();
this.forceUpdate();
}, times);
}
}
};
</script>
<style scoped lang='less'>
.no-data {
margin-top: 2.4rem;
}
.have-data {
margin-top: 0.2rem;
}
.my-scroll {
overflow: hidden;
height: 100%;
position: relative;
}
.pulldown-wrapper {
height: 0.5rem;
position: absolute;
top: -9px;
left: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
transition: all;
}
.scroll-content {
position: relative;
z-index: 2000;
}
.pull-up-box {
width: 100%;
height: 0.2rem;
// margin: 0.2rem 0 0.2rem 0;
color: #999;
font-size: 14px;
}
.refresh-txt {
height: 0.3rem;
width: 1rem;
border-radius: 3px;
background-color: black;
opacity: 0.7;
color: #fff;
z-index: 2999;
position: fixed;
top: 2rem;
left: 50%;
transform: translate(-50%, 0);
line-height: 0.3rem;
}
</style>
网友评论