vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件
Posted 每天都要进步一点点
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件相关的知识,希望对你有一定的参考价值。
1.下拉刷新和上拉加载更多组件
Scroller.vue
<!-- 下拉刷新 上拉加载更多 组件 --> <template> <div :style="marginTop" class="yo-scroll" :class="{\'down\':(state===0),\'up\':(state==1),refresh:(state===2),touch:touching}" @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)"> <section class="inner" :style="{ transform: \'translate3d(0, \' + top + \'px, 0)\' }"> <!-- 顶部提示语(刷新) --> <header class="pull-refresh"> <slot name="pull-refresh"> <span class="down-tip">下拉更新</span> <span class="up-tip">松开刷新数据</span> <span class="refresh-tip">加载中……</span> </slot> </header> <!-- 父组件 列表部分 --> <slot> </slot> <!-- 底部提示语(加载更多) --> <footer class="load-more"> <slot name="load-more"> <span v-show="downFlag === false">上拉加载更多</span> <span v-show="downFlag === true">加载中……</span> </slot> </footer> <!-- 暂无数据提示语 --> <div class="nullData" v-show="dataList.noFlag">暂无更多数据</div> </section> </div> </template> <script> export default { // 接收父组件参数 props: { marginTop: { default: "margin-top:40px;" }, // 默认高度 offset: { type: Number, default: 100 }, // 是否支持加载更多 enableInfinite: { type: Boolean, default: true }, // 是否支持刷新 enableRefresh: { type: Boolean, default: true }, // 是否显示\'暂无数据\' dataList: { default: false, required: false }, // 刷新方法 onRefresh: { type: Function, default: undefined, required: false }, // 加载更多方法 onInfinite: { type: Function, default: undefined, require: false } }, data() { return { top: 0, // 下拉高度 state: 0, // 状态: 0 下拉/ 1 上拉 / 2 刷新 startX: 0, // 手指滑动起始位置 X轴 startY: 0, // 手指滑动起始位置 Y轴 touching: false, // -webkit-overflow-scrolling infiniteLoading: false, // 加载更多效果 downFlag: false, //用来显示是否加载中 } }, methods: { // 手指刚开始滑动 touchStart(e) { this.startY = e.targetTouches[0].pageY; this.startX = e.targetTouches[0].pageX; this.startScroll = this.$el.scrollTop || 0; this.touching = true; //留着有用,不能删除 this.dataList.noFlag = false; // 默认 不显示\'暂无数据\' this.$el.querySelector(\'.load-more\').style.display = \'block\';// 实体化加载更多 }, // 手指移动中 touchMove(e) { if(!this.enableRefresh || this.dataList.noFlag || !this.touching) { return } let diff = e.targetTouches[0].pageY - this.startY - this.startScroll if(diff > 0) e.preventDefault() this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0) if(this.state === 2) { // 刷新中 return } if(this.top >= this.offset) { this.state = 1 } else { this.state = 0 } let more = this.$el.querySelector(\'.load-more\'); if(!this.top && this.state === 0) { more.style.display = \'block\'; } else { more.style.display = \'none\'; } }, // 手指结束滑动 touchEnd(e) { if(!this.enableRefresh) { return } this.touching = false if(this.state === 2) { // 刷新中 this.state = 2 this.top = this.offset return } if(this.top >= this.offset) { // 进行刷新 this.refresh() } else { // 取消刷新 this.state = 0 this.top = 0 } //用于判断滑动是否在原地 ----begin let endX = e.changedTouches[0].pageX, endY = e.changedTouches[0].pageY, dy = this.startY - endY, dx = endX - this.startX; //如果滑动距离太短 if(Math.abs(dx) < 2 && Math.abs(dy) < 2) { console.log("滑动距离太短") return; } //--------end-------- if(!this.enableInfinite || this.infiniteLoading) { return } let outerHeight = this.$el.clientHeight, innerHeight = this.$el.querySelector(\'.inner\').clientHeight, scrollTop = this.$el.scrollTop, ptrHeight = this.onRefresh ? this.$el.querySelector(\'.pull-refresh\').clientHeight : 0, bottom = innerHeight - outerHeight - scrollTop - ptrHeight; if(bottom <= this.offset && this.state === 0) { this.downFlag = true; this.infinite(); } else { this.$el.querySelector(\'.load-more\').style.display = \'none\'; this.downFlag = false; } }, // 刷新 refresh() { this.state = 2; this.top = this.offset; setTimeout(() => { this.onRefresh(this.refreshDone) }, 300); }, // 结束刷新 refreshDone() { this.state = 0 this.top = 0 }, // 加载更多 infinite() { this.infiniteLoading = true setTimeout(() => { this.onInfinite(this.infiniteDone); }, 2000); }, // 结束加载更多 infiniteDone() { this.infiniteLoading = false } } } </script> <style lang="less" scoped> .yo-scroll { // margin-top: 40px; // 解决有标题栏的bug font-size: 16px; position: absolute; top: 0; right: 0; bottom: 0; left: 0; overflow: auto; z-index: 100; height: auto; -webkit-overflow-scrolling: touch; .inner { position: absolute; top: -50px; width: 100%; height: auto; transition-duration: 300ms; .pull-refresh { position: relative; left: 0; top: 0; width: 100%; height: 50px; display: flex; display: -webkit-flex; align-items: center; justify-content: center; } .load-more { height: 50px; line-height: 50px; display: flex; text-align: center; align-items: center; justify-content: center; display: none; } .nullData { //暂无更多数据样式 font-size: 16px; color: #999999; height: 50px; line-height: 60px; text-align: center; } .down-tip, .refresh-tip, .up-tip { display: none; } .up-tip:before, .refresh-tip:before { content: \'\'; display: inline-block; width: 110px; height: 40px; font-size: 16px; background-size: 70% !important; position: absolute; top: 0; left: 20%; } .up-tip:before { background: url(../assets/images/down-logo.png) no-repeat left; } .refresh-tip:before { background: url(../assets/images/refresh-logo.gif) no-repeat left; } } } .yo-scroll.touch .inner { transition-duration: 0; } .yo-scroll.down .down-tip { display: block; } .yo-scroll.up .up-tip { display: block; } .yo-scroll.refresh .refresh-tip { display: block; } </style>
2.页面调用
LoadMore.vue
<!-- 加载更多 --> <template> <div> <!-- 标题栏 --> <mt-header title="加载更多"> <router-link to="/" slot="left"> <mt-button icon="back">返回</mt-button> </router-link> </mt-header> <!-- 列表 --> <div class="cont"> <m-scroller :on-refresh="onRefresh" :on-infinite="onInfinite" :dataList="scrollData" :marginTop="marginTop"> <ul> <li v-for="(item,index) in listdata">{{item.name}}</li> </ul> </m-scroller> </div> </div> </template> <script> import mScroller from \'../components/Scroller\' export default { components: { mScroller }, data() { return { marginTop:\'margin-top:40px;\', pageStart: 0, // 开始页数 pageEnd: 0, // 结束页数 listdata: [], // 数据列表 scrollData:{ noFlag: false //暂无更多数据显示 } } }, mounted: function() { // 首次请求数据 this.fetchData(); }, methods: { fetchData() { this.axios.get(\'/api/testData\').then((response) => { this.listdata = response.data.data.list; // 获取总页数 this.pageEnd = response.data.data.totalPage; // 还原 this.pageStart = 0; }) }, // 下拉刷新 onRefresh(done) { this.fetchData(); done(); // call done }, // 上拉加载更多 onInfinite(done) { this.pageStart++; // 加载条 let more = this.$el.querySelector(\'.load-more\'); // 判断是否显示加载条 if(this.pageStart > this.pageEnd){ //走完数据调用方法 this.scrollData.noFlag = true; }else{ let _this = this; this.axios.get(\'/api/testData\').then((response) => { _this.listdata = _this.listdata.concat(response.data.data.list); // 获取总页数 _this.pageEnd = response.data.data.totalPage; }) } // 隐藏加载条 more.style.display = \'none\'; done(); } } } </script> <style lang="less" scoped> ul { li { min-height: 50px; line-height: 50px; text-align: center; border: 1px solid red; } } // 隐藏滚动条 ::-webkit-scrollbar{ display:none; } </style>
3.效果图
以上是关于vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件的主要内容,如果未能解决你的问题,请参考以下文章
Android实现RecyclerView的下拉刷新和上拉加载更多
使用SwipeRefreshLayout和RecyclerView实现仿“简书”下拉刷新和上拉加载更多