vue移动端下拉刷新和上拉加载的实现代码

由于自身的项目比较简单,只有几个H5页面,用来嵌入app中,所有没有引入移动端的UI框架,但是介于能让用户在浏览H5页面时有下拉刷新和上拉加载,有更好的用户体验,自己写组件实现。

vue移动端下拉刷新和上拉加载的实现代码

1、下拉刷新DropDownRefresh.vue

<template lang="html"> <div @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)" :style="{transform: 'translate3d(0,' + top + 'px, 0)'}"> <header> <slot> <div v-if="dropDownState==1"> <img v-if="dropDownStateText.downImg" :src="require('../../assets/images/refreshAndReload/'+dropDownStateText.downImg)"> <span>{{dropDownStateText.downTxt}}</span> </div> <div v-if="dropDownState==2"> <img v-if="dropDownStateText.upImg" :src="require('../../assets/images/refreshAndReload/'+dropDownStateText.upImg)"> <span>{{dropDownStateText.upTxt}}</span> </div> <div v-if="dropDownState==3"> <img v-if="dropDownStateText.refreshImg" :src="require('../../assets/images/refreshAndReload/'+dropDownStateText.refreshImg)"> <span>{{dropDownStateText.refreshTxt}}</span> </div> </slot> </header> <slot></slot> </div> </template> <script> export default { props: { onRefresh: { type: Function, required: false } }, data () { return { defaultOffset: 100, // 默认高度, 相应的修改.releshMoudle的margin-top和.down-tip, .up-tip, .refresh-tip的height top: 0, scrollIsToTop: 0, startY: 0, isDropDown: false, // 是否下拉 isRefreshing: false, // 是否正在刷新 dropDownState: 1, // 显示1:下拉刷新, 2:松开刷新, 3:刷新中…… dropDownStateText: { downTxt: '下拉刷新', downImg: '', upTxt: '松开刷新', upImg: 'release.png', refreshTxt: '刷新中...', refreshImg: 'refresh.gif' } } }, created () { if (document.querySelector('.down-tip')) { // 获取不同手机的物理像素(dpr),以便适配rem this.defaultOffset = document.querySelector('.down-tip').clientHeight || this.defaultOffset } }, methods: { touchStart (e) { this.startY = e.targetTouches[0].pageY }, touchMove (e) { this.scrollIsToTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop // safari 获取scrollTop用window.pageYOffset if (e.targetTouches[0].pageY > this.startY) { // 下拉 this.isDropDown = true if (this.scrollIsToTop === 0 && !this.isRefreshing) { // 拉动的距离 let diff = e.targetTouches[0].pageY - this.startY - this.scrollIsToTop this.top = Math.pow(diff, 0.8) + (this.dropDownState === 3 ? this.defaultOffset : 0) if (this.top >= this.defaultOffset) { this.dropDownState = 2 e.preventDefault() } else { this.dropDownState = 1 e.preventDefault() } } } else { this.isDropDown = false this.dropDownState = 1 } }, touchEnd (e) { if (this.isDropDown && !this.isRefreshing) { if (this.top >= this.defaultOffset) { // do refresh this.refresh() this.isRefreshing = true console.log(`do refresh`) } else { // cancel refresh this.isRefreshing = false this.isDropDown = false this.dropDownState = 1 this.top = 0 } } }, refresh () { this.dropDownState = 3 this.top = this.defaultOffset setTimeout(() => { this.onRefresh(this.refreshDone) }, 1200) }, refreshDone () { this.isRefreshing = false this.isDropDown = false this.dropDownState = 1 this.top = 0 } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .refreshMoudle { width: 100%; margin-top: -100px; -webkit-overflow-scrolling: touch; /* ios5+ */ } .pull-refresh { width: 100%; color: #999; transition-duration: 200ms; } .refreshMoudle .down-tip, .up-tip, .refresh-tip { display: flex; align-items: center; justify-content: center; height: 100px; } .refreshMoudle .down-tip-img, .up-tip-img, .refresh-tip-img { width: 35px; height: 35px; margin-right: 5px; } </style>

2、上拉加载PullUpReload.vue

<template lang="html"> <div @touchstart="touchStart($event)" @touchmove="touchMove($event)" :style="{transform: 'translate3d(0,' + top + 'px, 0)'}"> <slot></slot> <footer> <slot> <div v-if="pullUpState==1"> <span>{{pullUpStateText.moreDataTxt}}</span> </div> <div v-if="pullUpState==2"> <span></span> <span>{{pullUpStateText.loadingMoreDataTxt}}</span> </div> <div v-if="pullUpState==3"> <span></span> <span>{{pullUpStateText.noMoreDataTxt}}</span> <span></span> </div> </slot> </footer> </div> </template> <script> export default { props: { parentPullUpState: { default: 0 }, onInfiniteLoad: { type: Function, require: false } }, data () { return { top: 0, startY: 0, pullUpState: 0, // 1:上拉加载更多, 2:加载中……, 3:我是有底线的 isLoading: false, // 是否正在加载 pullUpStateText: { moreDataTxt: '上拉加载更多', loadingMoreDataTxt: '加载中...', noMoreDataTxt: '我是有底线的' } } }, methods: { touchStart (e) { this.startY = e.targetTouches[0].pageY }, touchMove (e) { if (e.targetTouches[0].pageY < this.startY) { // 上拉 this.judgeScrollBarToTheEnd() } }, // 判断滚动条是否到底 judgeScrollBarToTheEnd () { let innerHeight = document.querySelector('.loadMoudle').clientHeight // 变量scrollTop是滚动条滚动时,距离顶部的距离 let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop // 变量scrollHeight是滚动条的总高度 let scrollHeight = document.documentElement.clientHeight || document.body.scrollHeight // 滚动条到底部的条件 if (scrollTop + scrollHeight >= innerHeight) { if (this.pullUpState !== 3 && !this.isLoading) { this.pullUpState = 1 this.infiniteLoad() // setTimeout(() => { // this.infiniteLoad() // }, 200) } } }, infiniteLoad () { this.pullUpState = 2 this.isLoading = true setTimeout(() => { this.onInfiniteLoad(this.infiniteLoadDone) }, 800) }, infiniteLoadDone () { this.pullUpState = 0 this.isLoading = false } }, watch: { parentPullUpState (curVal, oldVal) { this.pullUpState = curVal } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .load-more { width: 100%; color: #c0c0c0; background: #f7f7f7; } .moreData-tip, .loadingMoreData-tip, .noMoreData-tip { display: flex; align-items: center; justify-content: center; height: 150px; } .loadMoudle .icon-loading { display: inline-flex; width: 35px; height: 35px; background: url(../../assets/images/refreshAndReload/loading.png) no-repeat; background-size: cover; margin-right: 5px; animation: rotating 2s linear infinite; } @keyframes rotating { 0% { transform: rotate(0deg); } 100% { transform: rotate(1turn); } } .connectingLine { display: inline-flex; width: 150px; height: 2px; background: #ddd; margin-left: 20px; margin-right: 20px; } </style>

3、对两个组件的使用

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/60274be469471d307e3eb1fbc52158f1.html