下拉重新整理-掘友自制流程??

janto007發表於2018-03-29

效果展示

下拉重新整理-掘友自制流程??

掃碼體驗

下拉重新整理-掘友自制流程??

點選訪問demo地址
點選檢視原始碼

背景

下拉重新整理是移動端經常會用到的功能,看了各種各樣的ui庫,自己想搗鼓一下,研究下其中的原理,於是便有了這個例子。

頁面骨架

<template>
  <div class="pullDown">
    <!--loading-->
    <div class="pullDown__loading"></div>
    <!--scroll content-->
    <div class="pullDown__scroll">
        <ul class="pullDown__list"></ul>
    </div>
  </div>
</template>

複製程式碼

頁面基本樣式

.pullDown{
    background-color: #fff;
    position: absolute;
    z-index: 1;
    width: 100%;
    height: 100%;
    overflow-y: scroll;
    /* 增加該屬性,可以增加彈性 */
    -webkit-overflow-scrolling: touch;
    transform: translate3d(0, 0, 0);
    -webkit-transform: translate3d(0, 0, 0);    
}
.pullDonw__loading{
    position: absolute;
    left: 0;
    top: 0;
    display: block;
    overflow: hidden;
    width: 100%;
    height: 50px;
    text-align: center;
    padding: 16px 24px; 
    z-index: 2;
    background-color: #fff;
}
.pullDown__scroll{
    position: relative;
    z-index: 10;
    background-color: #fff;
    border-bottom: 1px solid #e8e8e8;
    border-top: 1px solid #e8e8e8;
}
複製程式碼

核心實現

下拉重新整理主要根據touchstart,touchmove,touchend三個事件進行判斷操作。

  1. touchstar觸發時,則判斷重新整理狀態中和容器到達頂端的情況,否則記錄當前位置資訊並設定可拉動狀態;
  2. touchemove觸發時,判斷重新整理狀態中和可拉動狀態,且當前移動位置需大於開始位置,則設定容器跟隨手指滾動;
  3. touchend觸發時,判斷重新整理狀態中和動畫中,分兩種情況:
    • 拉動距離超過重新整理情況,則執行動畫,重新整理動作
    • 拉動距離沒超過重新整理情況,則返回原始狀態
touchstart($event) {
    var vm= this;
    //判斷是否允許下拉
    if (!vm.isPull && !vm.isLoading && vm._scrollWrap.scrollTop == vm.offsetTop) {
      vm.isPull= true;
      vm.startPos= $event.touches[0].pageY;
    };
},
touchmove($event) {
    var vm= this;
    vm.endPos= $event.touches[0].pageY;
    
    //是否能拉動
    if (!vm.isLoading && vm.isPull && vm.startPos<vm.endPos) {
    
      vm.distance= (vm.endPos- vm.startPos)*vm.modulus;
      var offsetLoading= vm._loadingWrap.offsetHeight;
    
      if (vm.distance >= offsetLoading) {
        vm.pullStatus = 'up'
      }else{
        vm.pullStatus = 'down'
      }
      vm.moveTransition(vm.$refs.scroll, vm.distance, 0);
    }
},
touchend($event) {
    var vm= this;
    var offsetLoading= vm._loadingWrap.offsetHeight;
    // vm.isPull= false;
    
    //載入中 或 移動距離小於0不能移動
    if (vm.isLoading || vm.distance<=0 || vm.isBack) {return false;}
    
    //拉動距離大於臨界值
    if ( vm.distance>0 && vm.distance >= offsetLoading) {
    
      //執行重新整理動作
      vm.pullTransition({
        dom: vm._scrollWrap,
        begin: offsetLoading,
        end: vm.distance,
        duration: 500
      });
    
      //後臺重新整理資料
      vm.refresh();
    }else{
    
      vm.isBack= true;
      // 返回back初始狀態
      vm.pullTransition({
        dom: vm._scrollWrap,
        end: vm.distance,
        duration: 500,
        callback: vm.resetStatus
      });
    }
}
複製程式碼

下拉動畫實現

採用css動畫,則難以精準把握動畫結束的時間。故採用RequestAnimationFrame實現動畫,可監聽到結束狀態並處理回撥。有關 requestAnimationFrame參考以下資料:

/**
* [pullTransition 動畫拉動]
* @param  {[type]} dom [元素]
* @param  {[type]} begin [起始值]
* @param  {[type]} end [結束值]
* @param  {[type]} duration [時間]
* @param  {[type]} callback [回撥函式]
* @return {[type]}          [description]
*/
pullTransition(opt) {
    var vm= this;
    if (!opt.dom || !opt.end) {
      console.error('引數不足');
      return false;
    };
    
    var opt= {
      dom: opt.dom,
      currentTime: 0,
      begin: opt.begin? opt.begin: 0,
      end: opt.end,
      //相當一部分的瀏覽器的顯示頻率是16.7ms 約等於17
      duration: opt.duration? Math.ceil(opt.duration / 17) : 0,
      callback: opt.callback || false
    };
    
    var step= function() {
    
      //根據緩動演算法取得值
      var value = opt.end-vm.easeInOut(opt.currentTime, opt.begin, opt.end-opt.begin, opt.duration)+opt.begin;
      opt.dom.style.transform= 'translate3d(0,'+value+'px,0)';
    
      opt.currentTime++;
    
      //判斷是否到時間
      if (opt.currentTime <= opt.duration) {
           // 繼續運動
           requestAnimationFrame(step);
      } else {
          // 動畫結束
          if(opt.callback) opt.callback();
      } 
    };
    step();
}
/**
* [Linear 緩動演算法]
* @param {[type]} t [current time(當前時間)]
* @param {[type]} b [beginning value(初始值)]
* @param {[type]} c [change in value(變化量)]
* @param {[type]} d [duration(持續時間)]
*/
easeInOut(t, b, c, d) {
    if ((t /= d / 2) < 1) return c / 2 * t * t*t + b;
    return c / 2*((t -= 2) * t * t + 2) + b;      
}
複製程式碼

微信下拉顯示網址處理

在微信開啟一個頁面時,在頂部用力往下拉的時候會出現如下圖情況,對於下拉重新整理來說體驗比較差。我在網上搜尋了下找到兩種方式處理,供各位參考。本例子採用第一種方式,至於採用的依據目前還未深入比較,後續再深入調查。

下拉重新整理-掘友自制流程??


至此,下拉重新整理功能完成,任何意見和建議歡迎提出。

相關文章