272 lines
6.0 KiB
Vue
272 lines
6.0 KiB
Vue
<template>
|
||
<view class="you-scroll" ref="youScroll">
|
||
<view class="pullDown" :style="{ transform: 'translateY('+translateY+'px)', transition: isDown ? '0s' : '0.3s' }">
|
||
<slot name="pullDown">
|
||
<!-- <img src="@/static/pullDown.jpg" :class="{'down-icon': true,'animate': pullDownStatus == 3}"></img> -->
|
||
<span>
|
||
<block v-if="pullDownStatus == 1">{{downPullToRefresh}}</block>
|
||
<block v-if="pullDownStatus == 2">{{downReleaseToRefresh}}</block>
|
||
<block v-if="pullDownStatus == 3">{{downRefreshing}}</block>
|
||
</span>
|
||
</slot>
|
||
</view>
|
||
<scroll-view class="you-scroll-inner" ref="youScrollInner" :scroll-top.stop="scrollToTop" scroll-with-animation scroll-y :style="{ transform: 'translateY('+translateY+'px)', transition: isDown ? '0s' : 'transform 0.3s' }"
|
||
@touchstart.stop="startFn" @touchmove.stop="moveFn" @touchend.stop="endFn" @touchcancel.stop="endFn" @scroll.stop="scroll">
|
||
<view class="you-scroll-content">
|
||
<slot></slot>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
scrollToTop: 0,
|
||
scrollTop: 0,
|
||
oldTop: 0,
|
||
sPageY: 0,
|
||
mPageY: 0,
|
||
ePageY: 0,
|
||
translateY: 0,
|
||
pullDownStatus: 1, // 1:下拉刷新 2:松开刷新 3:刷新中
|
||
isDown: false
|
||
};
|
||
},
|
||
props: {
|
||
pullDownDistance: {
|
||
type: Number,
|
||
default: 50 // 下拉刷新距离
|
||
},
|
||
reachBottomDistance: {
|
||
type: Number,
|
||
default: 30 // 上拉加载距离
|
||
},
|
||
downPullToRefresh: {
|
||
type: String,
|
||
default: '下拉刷新'
|
||
},
|
||
downReleaseToRefresh: {
|
||
type: String,
|
||
default: '松开刷新'
|
||
},
|
||
downRefreshing: {
|
||
type: String,
|
||
default: '刷新中…'
|
||
},
|
||
},
|
||
methods: {
|
||
startFn(e) {
|
||
this.isDown = true;
|
||
this.sPageY = e.changedTouches[0].pageY;
|
||
this.pointY = this.translateY;
|
||
},
|
||
moveFn(e) {
|
||
let view = uni.createSelectorQuery().in(this).select(".you-scroll-inner");
|
||
view.fields({
|
||
size: true,
|
||
scrollOffset: true
|
||
}, data => {
|
||
this.scrollTop = data.scrollTop;
|
||
this.mPageY = e.changedTouches[0].pageY;
|
||
if (this.scrollTop <= 0) {
|
||
let translateY = ((this.mPageY - this.sPageY) / 2) + this.pointY;
|
||
this.translateY = (translateY < 0 ? 0 : translateY);
|
||
|
||
if(this.pullDownStatus != 3) {
|
||
if(this.translateY < this.pullDownDistance) {
|
||
this.pullDownStatus = 1;
|
||
} else if(this.translateY >= this.pullDownDistance) {
|
||
this.pullDownStatus = 2;
|
||
}
|
||
}
|
||
}
|
||
}).exec();
|
||
|
||
},
|
||
endFn(e) {
|
||
this.isDown = false;
|
||
this.ePageY = e.changedTouches[0].pageY;
|
||
setTimeout(() => {
|
||
this.translateY = this.translateY >= this.pullDownDistance ? this.pullDownDistance : 0;
|
||
if(this.pullDownStatus == 2) { // 开始刷新
|
||
this.pullDownStatus = 3;
|
||
this.$emit('onPullDown',this.endPullDown);
|
||
}
|
||
},100)
|
||
|
||
|
||
},
|
||
endPullDown(mm) {
|
||
if(this.timeout) clearTimeout(this.timeout);
|
||
this.timeout = setTimeout(() => {
|
||
this.translateY = 0;
|
||
this.pullDownStatus = 1;
|
||
}, mm || 0);
|
||
},
|
||
prevent(e) {
|
||
if(this.translateY > 0) {
|
||
e.preventDefault();
|
||
}
|
||
},
|
||
scroll(e) {
|
||
this.$emit('onScroll',e);
|
||
this.oldTop = e.detail.scrollTop;
|
||
|
||
if(this.timeout) clearTimeout(this.timeout);
|
||
this.timeout = setTimeout(() => {
|
||
this.scrolltolower(e);
|
||
},20);
|
||
},
|
||
scrolltolower(e) {
|
||
let view = uni.createSelectorQuery().in(this).select(".you-scroll-inner");
|
||
view.fields({
|
||
size: true,
|
||
scrollOffset: true
|
||
}, data => {
|
||
if(data.scrollTop >= (e.detail.scrollHeight - data.height - this.reachBottomDistance)) {
|
||
this.$emit('onLoadMore',e);
|
||
}
|
||
}).exec();
|
||
|
||
},
|
||
isWeixinCient(){
|
||
var ua = navigator.userAgent.toLowerCase();
|
||
if(ua.match(/MicroMessenger/i)=="micromessenger") {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
},
|
||
goTop(top) {
|
||
this.scrollToTop = this.oldTop;
|
||
this.$nextTick(function() {
|
||
this.scrollToTop = top || 0;
|
||
});
|
||
}
|
||
},
|
||
mounted() {
|
||
// #ifdef H5
|
||
if(this.isWeixinCient()) {
|
||
document.body.addEventListener('touchmove', this.prevent);
|
||
}
|
||
// #endif
|
||
},
|
||
destroyed() {
|
||
// #ifdef H5
|
||
if(this.isWeixinCient()) {
|
||
document.body.removeEventListener('touchmove', this.prevent);
|
||
}
|
||
// #endif
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.you-scroll {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
position: relative;
|
||
// background-color: #eee;
|
||
}
|
||
.you-scroll .pullDown {
|
||
width: 100%;
|
||
height: 40px;
|
||
line-height: 50px;
|
||
text-align: center;
|
||
font-size: 14px;
|
||
overflow: hidden;
|
||
transform: translateY(-100%);
|
||
position: absolute;
|
||
top: -40px;
|
||
left: 0;
|
||
}
|
||
.you-scroll .pullDown .down-icon {
|
||
width: 40px;
|
||
height: 32px;
|
||
display: inline-block;
|
||
vertical-align: middle;
|
||
}
|
||
.you-scroll .pullDown .animate {
|
||
-webkit-animation: scaleIcon 1s infinite linear;
|
||
-moz-animation: scaleIcon 1s infinite linear;
|
||
-ms-animation: scaleIcon 1s infinite linear;
|
||
animation: scaleIcon 1s infinite linear;
|
||
}
|
||
.you-scroll .pullDown span {
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
display: inline-block;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.you-scroll .you-scroll-inner {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
.you-scroll-content {
|
||
overflow: hidden;
|
||
}
|
||
|
||
@-webkit-keyframes scaleIcon {
|
||
0% {
|
||
transform: scaleY(1);
|
||
}
|
||
40% {
|
||
transform: scaleY(0.8);
|
||
}
|
||
80% {
|
||
transform: scaleY(0.9);
|
||
}
|
||
100% {
|
||
transform: scaleY(1);
|
||
}
|
||
}
|
||
@-moz-keyframes scaleIcon {
|
||
0% {
|
||
transform: scaleY(1);
|
||
}
|
||
40% {
|
||
transform: scaleY(0.8);
|
||
}
|
||
80% {
|
||
transform: scaleY(0.9);
|
||
}
|
||
100% {
|
||
transform: scaleY(1);
|
||
}
|
||
}
|
||
@-ms-keyframes scaleIcon {
|
||
0% {
|
||
transform: scaleY(1);
|
||
}
|
||
40% {
|
||
transform: scaleY(0.8);
|
||
}
|
||
80% {
|
||
transform: scaleY(0.9);
|
||
}
|
||
100% {
|
||
transform: scaleY(1);
|
||
}
|
||
}
|
||
@keyframes scaleIcon {
|
||
0% {
|
||
transform: scaleY(1);
|
||
}
|
||
40% {
|
||
transform: scaleY(0.8);
|
||
}
|
||
80% {
|
||
transform: scaleY(0.9);
|
||
}
|
||
100% {
|
||
transform: scaleY(1);
|
||
}
|
||
}
|
||
</style>
|