| <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="scrollToTop" scroll-with-animation scroll-y :style="{ transform: 'translateY('+translateY+'px)', transition: isDown ? '0s' : 'transform 0.3s' }"  | 
|          @touchstart="startFn" @touchmove="moveFn" @touchend="endFn" @touchcancel="endFn" @scroll="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> |