200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 移动端下拉刷新 兼容ios Android及微信浏览器

移动端下拉刷新 兼容ios Android及微信浏览器

时间:2019-03-17 07:23:34

相关推荐

移动端下拉刷新 兼容ios Android及微信浏览器

先看一下效果图

下拉效果的样子参考的新浪微博,滚动加载是ydui的滚动加载组件

因为滚动加载使用的ydui的组件,我这里便不再累述

在线体验点这里

首先分析下拉刷新是怎么实现的

1.页面滚动到顶部时,用户手指向下拖动2.页面整体开始随着手指向下移动,同时出现下拉的动画3.用户拖动超过指定长度之后松开手指,页面开始回弹并且执行加载中的动画4.加载完成之后执行结束的动画

实现原理

一、touchstart事件中1.判断是不是滚动到了顶部,如果不是则什么也不用做2.判断上次的下拉刷新是不是结束了,如果没有则阻止浏览器默认行为3.如果滚动到了顶部 且 没有进行中的下拉刷新 则记录触摸的位置event.touches[0].clientY二、touchmove事件中1.判断是不是滚动到了顶部,如果不是则什么也不用做2.判断上次的下拉刷新是不是结束了,如果没有则阻止浏览器默认行为3.如果滚动到了顶部 且 没有进行中的下拉刷新1.判断手指是向上滑还是向下滑,向上则正常滚动页面,向下则执行下拉刷新2.如果手指向下拉,则判断滑动的距离是否超过了指定的距离,超过了则改变动画效果(由下拉刷新-> 释放刷新)三、touchend事件中与touchmove中判断同,唯一不同的是滑动的距离是否超过了指定的距离触发回调并且执行刷新中的动画

获取页面滚动的位置(或者是div内部滚动位置)

/*** 传入一个dom对象,返回获取滚动的位置* @method getScrollTop* @param {dom} dom节点* @return {Number} 滚动的位置*/function getScrollTop(element) {if (element === window) {return Math.max(window.pageYOffset || 0,document.documentElement.scrollTop)} else {return element.scrollTop}}

事件处理

//touchstart事件function touchStartHandler(event) {//正在执行下拉刷新则返回if (this.touches.loading) {event.preventDefault()return}//当向下滚动了则直接返回//this.getScrollTop(this.scrollview)获取元素滚动的位置,实现方法见源码//this.$refs.dragBox.getBoundingClientRect().top为元素距离窗口顶部的距离//this.offsetTop为页面初始化时 this.$refs.dragBox.getBoundingClientRect().top的值if (this.getScrollTop(this.scrollview) > 0 ||this.$refs.dragBox.getBoundingClientRect().top < this.offsetTop) {return}//数据初始化this.touches.loading = false //是否在下拉刷新回调中this.touches.startClientY = 0 //触摸初始位置this.touches.isDraging = false //是否开始下拉刷新this.touches.statusText = '下拉刷新' //下拉刷新动画中的描述文字this.moveOffset = 0 //手指滑动的距离//记录触摸位置this.touches.startClientY = event.touches[0].clientY}//touchmove事件function touchMoveHandler(event) {const touches = this.touches//记录当前触摸位置,为了和下一个触摸位置作比较,判断是向上还是向下移动touches.currentClientY = event.touches[0].clientY//当向下滚动了则直接返回if (this.getScrollTop(this.scrollview) > 0 ||this.$refs.dragBox.getBoundingClientRect().top < this.offsetTop) {this.touches.isDraging = false //没有开始下拉刷新this.moveOffset = 0 //手指滑动的距离0return}//正在执行下拉刷新则返回if (this.touches.loading) {event.preventDefault()return}//当前触摸的位置const currentY = event.touches[0].clientY//防止手指直接下滑造成页面不能正常的滚动if (!touches.isDraging && currentY < touches.startClientY) {return}//手指先先下拉,再向上滑,说明此时手指已经在触摸位置上方了if (touches.isDraging &&(currentY - touches.startClientY < 0 ||this.$refs.dragBox.getBoundingClientRect().top <this.offsetTop)) {// this.isDragToUp = true;event.preventDefault()return}//手指向下滑if (touches.isDraging && this.getScrollTop(this.scrollview) === 0) {event.preventDefault()}// //开始下拉刷新this.touches.isDraging = true//手指滑动的距离let deltaSlide = currentY - touches.startClientY//如果超过了指定的距离, 达到了释放更新的条件//touches.distance为顶部加载中动画的高度//this.double为手指移动距离和页面实际移动距离的倍数if (deltaSlide >= touches.distance * this.double) {this.touches.statusText = '释放更新'} else {this.touches.statusText = '下拉刷新'}//记录滑动的距离this.moveOffset = deltaSlide}//touchend事件function touchEndHandler(event) {const touches = this.touches//正在执行下拉刷新则返回if (this.touches.loading) {event.preventDefault()return}//当向下滚动了则直接返回if (this.getScrollTop(this.scrollview) > 0 ||this.$refs.dragBox.getBoundingClientRect().top < this.offsetTop) {this.touches.isDraging = falsethis.moveOffset = 0return}const currentY = event.changedTouches[0].clientY//说明此时手指已经在触摸位置上方了if (currentY - touches.startClientY < 0 ||this.$refs.dragBox.getBoundingClientRect().top < this.offsetTop) {this.touches.isDraging = falseevent.preventDefault()return}//下拉刷新阻止浏览器默认行为if (this.getScrollTop(this.scrollview) === 0) {event.preventDefault()}//手指滑动的距离let deltaSlide = currentY - touches.startClientY//如果超过了指定的距离if (deltaSlide >= touches.distance * this.double) {//进行更新的回调及动画的改变,这部分见源码,耐心的看源码,还是能很容易看明白的some code...} else {this.touches.isDraging = false//距离不够则不刷新this.Retract(0, false)}}

上方只展示了主要部分,完整源码见文末

然后我把下拉刷新和上拉加载封装为一个vue组件

使用方法

//引入import YdInfinitescroll from './components/InfiniteScroll.vue'//注册components: {YdInfinitescroll }//使用<yd-infinitescroll:pullcallback="pullcallback":callback="callback"ref="infinitescrollDemo"><div slot='list'>...这里放你的内容</div></yd-infinitescroll>

说明:

1.传入callback参数表示开启滚动加载功能1.this.$refs.infinitescrollDemo.$emit('ydui.infinitescroll.finishLoad')表示单次数据请求完毕2.this.$refs.infinitescrollDemo.$emit('ydui.infinitescroll.loadedDone')表示所有数据请求完毕3.this.$refs.infinitescrollDemo.$emit('ydui.infinitescroll.reInit')表示重新初始化2.传入pullcallback参数表示开启下拉刷新功能1.更新成功请调用this.$refs.infinitescrollDemo.$emit('ydui.pullrefresh.finishLoad.success',true) 参数 true 开始提示, false 关闭提示, 默认true2.更新成功请调用this.$refs.infinitescrollDemo.$emit('ydui.pullrefresh.finishLoad.fail',true) 参数 true 开始提示, false 关闭提示, 默认true3.传入pullTipBgColor参数来修改下拉刷新成功状态的背景色,默认蓝色(#171dca)

组件源码,直接copy源码保存为InfiniteScroll.vue即可开始使用

<template><div><!-- 下拉刷新 --><divclass="dragBox"ref="dragBox":style="moveOffset? {transform: `translateY(${moveOffset / double}px)` }: ''"><!-- 下拉刷新动画效果 --><divclass="yd-pullTip":style="{height: `${moveOffset / double}px`,top: `-${moveOffset / double}px`,paddingBottom:moveOffset / double > (touches.distance - 20) / 2? (touches.distance - 20) / 2 + 'px': `${moveOffset / double}px`}"><imgv-if="touches.loading"src="data:image/gif;base64,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"/><imgv-else:class="{ rotate: moveOffset >= touches.distance * double }"src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAA4CAYAAAB3yEEBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OEFFN0NBNENDQkVEMTFFOTg3ODBCRjE0Q0NBQTdFMDEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OEFFN0NBNERDQkVEMTFFOTg3ODBCRjE0Q0NBQTdFMDEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4QUU3Q0E0QUNCRUQxMUU5ODc4MEJGMTRDQ0FBN0UwMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4QUU3Q0E0QkNCRUQxMUU5ODc4MEJGMTRDQ0FBN0UwMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pk84QwMAAALZSURBVHja7Jm7jtpAFIbtgeXiBhvIG6RaEFRcnmIfIc02W20RVtr0KZIiaTYNTV6CJq/ApYpAW21DQwei4SIhQeZf+aDRrD0e20iJlBkJgeZ2vvnPmcN4bK9WKytluRF+D9JMlE0zeLvd3s1ms956vX7ved5zvV5/VywWf8r9bNu2TqdT5Hx2HGXESQEyHo+/73Y7h9odx1m32+2HpEBMB4CKCsSvd0ej0ROvv5Xn0VEmEkaeJAyECup5+7cgoNQwMghf+RkkbLVQaDKZxAZiUa4RVnwLRfb7vaPqR2Wz2bhxFWK6rvFjwdF1Z1QMJXITKaICUe2WODHEomJkOBw+BcVILpc7yP0zmYyVz+cPSRViKpCwGOF5ZNtqtT69mYwxq9vt3hcKhW0ShZjKNSIIFYDwxNbjCW4RNBb1nU6nFwQEhVRALGT7vroGbhFdAwM+SF8lN9oBRC4T51ABMVH+oIQG6UkRGIAhnWyKfuQyOQUQEOyJIcCIXAZBHe0Qcg3/7kfllyCFwlzGE+MXKER2GMWImFnFrSrESF+GiIJCuwwkjiGFeGx+IDfd8GPAx4hg7esmuqB20WXyGC6AO51OH8Hxqgw/RlzLq/Rj5J5AdOJEVXCsCHIZ5l0ul9fnAC6VSnN51wAk6FySpoTFEOwTzKDRaHzlJ7U5dk61Wn2GpDKIbtDq7jLYgb1yufwC++DICh0W3OCBK3SV9iyr4zIeiwvf1vnsnMWKj8cjVj4Qt7P8x6d7jtU9uvLPrzdJjwzLOyCsPm1RzcOSDrwkEBaNT9b6C0XeDATHrH+oGBgDY2AMjIExMAbGwBgYA2NgDMz/BJPk1iI2DD394cZC9dia5NGYJVmxf5NwFed5+iLvm8IMMcYO5Ar6xuWPf8dzho7jtsQxAxjXdefiqj3P+w3FyHBcV6UJ4EGz2fxcqVRe8AID12K1Wu2HleLWy477KjngButir5L/CDAAX5Ad05wlsggAAAAASUVORK5CYII="/>{{touches.statusText }}</div><!-- 下拉刷新提示效果 --><div class="yd-Tip" v-if="pullupdateStatus">{{pullupdateText }}<span:style="pullupdateText === '更新成功'? `backgroundColor: ${pullTipBgColor};`: 'backgroundColor: #aeaeae;'"></span></div><slot name="list"></slot></div><div ref="tag" style="height: 0;"></div><div class="yd-list-loading" v-if="!isDone"><div v-show="isLoading"><slot name="loadingTip"><template><svgxmlns="/2000/svg"viewBox="0 0 100 100"preserveAspectRatio="xMidYMid"class="lds-ellipsis"><circle cx="84" cy="50" r="5.04711" fill="#f3b72e"><animateattributeName="r"values="10;0;0;0;0"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="0s"></animate><animateattributeName="cx"values="84;84;84;84;84"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="0s"></animate></circle><circle cx="66.8398" cy="50" r="10" fill="#E8574E"><animateattributeName="r"values="0;10;10;10;0"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="-0.85s"></animate><animateattributeName="cx"values="16;16;50;84;84"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="-0.85s"></animate></circle><circle cx="32.8398" cy="50" r="10" fill="#43A976"><animateattributeName="r"values="0;10;10;10;0"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="-0.425s"></animate><animateattributeName="cx"values="16;16;50;84;84"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="-0.425s"></animate></circle><circle cx="16" cy="50" r="4.95289" fill="#304153"><animateattributeName="r"values="0;10;10;10;0"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="0s"></animate><animateattributeName="cx"values="16;16;50;84;84"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="0s"></animate></circle><circle cx="16" cy="50" r="0" fill="#f3b72e"><animateattributeName="r"values="0;0;10;10;10"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="0s"></animate><animateattributeName="cx"values="16;16;16;50;84"keyTimes="0;0.25;0.5;0.75;1"keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1"calcMode="spline"dur="1.7s"repeatCount="indefinite"begin="0s"></animate></circle></svg></template></slot></div></div><div class="yd-list-donetip" v-show="!isLoading && isDone"><slot name="doneTip">没有更多数据了</slot></div></div></template><script type="text/babel">export default {name: 'BaseInfinitescroll',data() {return {isLoading: false,isDone: false,num: 1,touches: {loading: false, //是否在下拉刷新回调中distance: 60, //滑动距离大于100时可释放刷新startClientY: 0,currentClientY: Math.pow(2, 32), //当前触摸位置isDraging: false, //是否开始下拉刷新statusText: '下拉刷新' //此时的状态描述},moveOffset: 0, //手指下拉的长度滚动的double: 3, //手滑动距离与下拉距离的倍数// step: 20 //松开手指界面向上滑动的速度time: 100,pullupdateStatus: false, //是否展示下拉刷新更新后的提示pullupdateText: '更新成功' //展示下拉刷新更新后的提示}},props: {callback: {type: Function},pullcallback: {type: Function},distance: {default: 0,validator(val) {return /^\d*$/.test(val)}},scrollTop: {type: Boolean,default: true},pullTipBgColor: {type: String,default: '#1989fa'}},methods: {init() {if (this.scrollTop) {if (this.scrollview === window) {window.scrollTo(0, 0)} else {this.scrollview.scrollTop = 0}}this.scrollview.addEventListener('scroll',this.throttledCheck,false)this.$on('ydui.infinitescroll.loadedDone', () => {this.isLoading = falsethis.isDone = true})this.$on('ydui.infinitescroll.finishLoad', () => {this.isLoading = false})this.$on('ydui.infinitescroll.reInit', () => {this.isLoading = falsethis.isDone = false})},pullinit() {const dragBox = this.$refs.dragBoxdragBox.addEventListener('touchstart', this.touchStartHandler)dragBox.addEventListener('touchmove', this.touchMoveHandler)dragBox.addEventListener('touchend', this.touchEndHandler)//防止微信浏览器下拉出现域名document.body.addEventListener('touchmove', this.stopDragEvent, {passive: false //调用阻止默认行为})//容器距离顶部的距离this.offsetTop = this.$refs.dragBox.getBoundingClientRect().top//上拉加载完成this.$on('ydui.pullrefresh.finishLoad.success', (tip = true) => {this.pullupdateText = '更新成功'this.Retract(0, tip)})this.$on('ydui.pullrefresh.finishLoad.fail', (tip = true) => {this.pullupdateText = '更新失败'this.Retract(0, tip)})// eslint-disable-next-line no-unused-varsthis.$on('ydui.pullrefresh.finishLoad.load', (tip = true) => {this.touches.statusText = '加载中'this.touches.loading = truethis.moveOffset = this.double * this.touches.distancethis.pullupdateStatus = false})},scrollHandler() {if (this.isLoading || this.isDone) returnconst scrollview = this.scrollviewconst contentHeight = document.body.offsetHeightconst isWindow = scrollview === windowconst offsetTop = isWindow? 0: scrollview.getBoundingClientRect().topconst scrollviewHeight = isWindow? contentHeight: scrollview.offsetHeightif (!scrollview) {// eslint-disable-next-lineconsole.warn("Can't find the scrollview!")return}if (!this.$refs.tag) {// eslint-disable-next-lineconsole.warn("Can't find the refs.tag!")return}const tagOffsetTop =Math.floor(this.$refs.tag.getBoundingClientRect().top) - 1const distance =!!this.distance && this.distance > 0? ~~this.distance: Math.floor(contentHeight / 10)if (tagOffsetTop > offsetTop &&tagOffsetTop - (distance + offsetTop) * this.num <=contentHeight &&this.$el.offsetHeight > scrollviewHeight) {this.isLoading = truethis.callback && this.callback()this.num++}},throttle(method, context) {clearTimeout(method.tId)method.tId = setTimeout(() => {method.call(context)}, 30)},throttledCheck() {this.throttle(this.scrollHandler)},getScrollview(el) {let currentNode = elwhile (currentNode &&currentNode.tagName !== 'HTML' &&currentNode.tagName !== 'BODY' &&currentNode.nodeType === 1) {let overflowY = document.defaultView.getComputedStyle(currentNode).overflowYif (overflowY === 'scroll' || overflowY === 'auto') {return currentNode}currentNode = currentNode.parentNode}return window},/*** 获取滚动的位置* @method getScrollTop* @return {Number} 滚动的位置*/getScrollTop(element) {if (element === window) {return Math.max(window.pageYOffset || 0,document.documentElement.scrollTop)} else {return element.scrollTop}},touchStartHandler(event) {//正在执行下拉刷新则返回if (this.touches.loading) {event.preventDefault()return}//当向下滚动了则直接返回if (this.getScrollTop(this.scrollview) > 0 ||this.$refs.dragBox.getBoundingClientRect().top < this.offsetTop) {return}//数据初始化this.touches.loading = falsethis.touches.startClientY = 0this.touches.isDraging = falsethis.touches.statusText = '下拉刷新'this.moveOffset = 0//记录触摸位置// this.touches.startClientX = event.touches[0].clientXthis.touches.startClientY = event.touches[0].clientY},touchMoveHandler(event) {const touches = this.touches//记录当前触摸位置touches.currentClientY = event.touches[0].clientY//当向下滚动了则直接返回if (this.getScrollTop(this.scrollview) > 0 ||this.$refs.dragBox.getBoundingClientRect().top < this.offsetTop) {// this.dragTip.translate = 0;// this.resetParams();this.touches.isDraging = falsethis.moveOffset = 0return}//正在执行下拉刷新则返回if (this.touches.loading) {event.preventDefault()return}// console.log(this.getScrollTop(this.scrollview))// console.log('执行了')const currentY = event.touches[0].clientY// const currentX = event.touches[0].clientX//防止手指直接下滑造成页面不能正常的滚动if (!touches.isDraging && currentY < touches.startClientY) {return}//手指先先下拉,再向上滑,说明此时手指已经在触摸位置上方了if (touches.isDraging &&(currentY - touches.startClientY < 0 ||this.$refs.dragBox.getBoundingClientRect().top <this.offsetTop)) {// this.isDragToUp = true;event.preventDefault()return}//手指向下滑if (touches.isDraging && this.getScrollTop(this.scrollview) === 0) {event.preventDefault()}// //开始下拉刷新this.touches.isDraging = true// const touchAngle =//(Math.atan2(// Math.abs(currentY - touches.startClientY),// Math.abs(currentX - touches.startClientX)//) *// 180) ///Math.PI// if (90 - touchAngle > 45) return//手指滑动的距离let deltaSlide = currentY - touches.startClientY//如果超过了指定的距离, 达到了释放更新的条件if (deltaSlide >= touches.distance * this.double) {this.touches.statusText = '释放更新'} else {this.touches.statusText = '下拉刷新'}//记录滑动的位置this.moveOffset = deltaSlide// console.log(this.moveOffset)},touchEndHandler(event) {const touches = this.touches// console.log(this.touches.isDraging)//正在执行下拉刷新则返回if (this.touches.loading) {event.preventDefault()return}//当向下滚动了则直接返回if (this.getScrollTop(this.scrollview) > 0 ||this.$refs.dragBox.getBoundingClientRect().top < this.offsetTop) {this.touches.isDraging = falsethis.moveOffset = 0return}const currentY = event.changedTouches[0].clientY// const currentX = event.changedTouches[0].clientX//说明此时手指已经在触摸位置上方了if (currentY - touches.startClientY < 0 ||this.$refs.dragBox.getBoundingClientRect().top < this.offsetTop) {this.touches.isDraging = falseevent.preventDefault()return}//下拉刷新阻止浏览器默认行为if (this.getScrollTop(this.scrollview) === 0 &&currentY !== this.touches.startClientY) {event.preventDefault()}//手指滑动的距离let deltaSlide = currentY - touches.startClientY//如果超过了指定的距离if (deltaSlide >= touches.distance * this.double) {//进行更新的动画this.touches.statusText = '加载中'// alert('下拉刷新')this.touches.startClientY = 0this.touches.isDraging = falsethis.Retract(touches.distance * this.double)return} else {this.touches.isDraging = false//距离不够则不刷新this.Retract(0, false)}},stopDragEvent(event) {this.touches.isDraging && event.preventDefault()},Retract(offsetTop, tip) {let timer = setInterval(() => {//根据时间计算出每次运动的距离// 总时间 / 每次运动时间 = 运动次数// 总长度 / 运动次数 = 每次运动距离let step = ((this.touches.distance * this.double) /((this.time * 60) / 1000).toFixed(2)).toFixed(2)if (this.moveOffset - step > offsetTop) {this.moveOffset -= step} else {this.moveOffset = offsetTopclearInterval(timer)if (offsetTop !== 0) {this.touches.loading = truethis.pullcallback && this.pullcallback()} else {//重置this.touches.loading = falsethis.touches.startClientY = 0this.touches.isDraging = falsethis.touches.statusText = '下拉刷新'//执行加载中动画if (tip) {//执行更新成功或者失败动画this.pullupdateStatus = truesetTimeout(() => {this.pullupdateStatus = false}, 1000)}}}}, 1000 / 60)}},mounted() {// console.log(this.distance, this.touches)this.scrollview = this.getScrollview(this.$el)if (this.callback) {this.init()}if (this.pullcallback) {this.pullinit()}},beforeDestroy() {this.scrollview.removeEventListener('scroll', this.throttledCheck)this.$refs.dragBox.removeEventListener('touchstart',this.touchStartHandler)this.$refs.dragBox.removeEventListener('touchmove',this.touchMoveHandler)this.$refs.dragBox.removeEventListener('touchend', this.touchEndHandler)document.body.removeEventListener('touchmove', this.stopDragEvent)}}</script><style lang="scss" scoped>@keyframes intact {0% {border-radius: 50%;}100% {border-radius: 0%;}}.dragBox {position: relative;}.yd {&-list-loading {padding: 0.1rem 0;text-align: center;font-size: 0.26rem;color: #999;height: 0.66rem;box-sizing: content-box;&-box {height: 0.66rem;overflow: hidden;line-height: 0.66rem;}img {height: 0.66rem;display: inline-block;}svg {width: 0.66rem;height: 0.66rem;}}&-list-donetip {font-size: 0.24rem;text-align: center;padding: 0.25rem 0;color: #777;}&-pullTip {text-align: center;font-size: 0.24rem;position: absolute;left: 0;right: 0;background: #eeeeee;color: #a5a5a5;overflow: hidden;display: flex;align-items: flex-end;justify-content: center;img {height: 20px;margin-right: 12px;margin-bottom: -1px;transition: transform 0.1s linear;transform: rotate(180deg);}img.rotate {transform: rotate(0deg);}}&-Tip {z-index: 99999999;position: absolute;left: 0;right: 0;top: 0;height: 36px;line-height: 36px;font-size: 0.26rem;overflow: hidden;text-align: center;color: #fff;span {position: absolute;top: 0;left: 0;z-index: -1;display: block;width: 100%;padding-top: 100%;border-radius: 50%;animation: intact 0.1s linear forwards;}}}</style>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。