最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解vue mint-ui源碼解析之loadmore組件

 更新時(shí)間:2017年10月11日 12:08:31   作者:qiaoba_gogo  
本篇文章主要介紹了vue mint-ui源碼解析之loadmore組件,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

本文介紹了vue mint-ui源碼解析之loadmore組件,分享給大家,具體如下:

接入

官方接入文檔mint-ui loadmore文檔

接入使用Example

html

<div id="app">
  <mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :max-distance="150"
         @top-status-change="handleTopChange" ref="loadmore">

    <div slot="top" class="mint-loadmore-top">
      <span v-show="topStatus === 'pull'" :class="{ 'rotate': topStatus === 'drop' }">↓</span>
      <span v-show="topStatus === 'loading'">Loading...</span>
      <span v-show="topStatus === 'drop'">釋放更新</span>
    </div>

    <ul class="scroll-wrapper">
      <li v-for="item in list" @click="itemClick(item)">{{ item }}</li>
    </ul>

  </mt-loadmore>
</div>

css

<link rel="stylesheet"  rel="external nofollow" >
*{
  margin: 0;
  padding: 0;
}
html, body{
  height: 100%;
}

#app{

  height: 100%;
  overflow: scroll;
}
.scroll-wrapper{
  margin: 0;
  padding: 0;
  list-style: none;

}
.scroll-wrapper li{
  line-height: 120px;
  font-size: 60px;
  text-align: center;
}

js 

<!-- 先引入 Vue -->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- 引入組件庫 -->
<script src="https://unpkg.com/mint-ui/lib/index.js"></script>
<script>
  new Vue({
    el: '#app',
    data: {
      list: [],
      allLoaded: false,
      topStatus: ''
    },
    created: function () {
      var i =0, len=20;
      for (; i< len; i++){
        this.list.push('demo' + i);
      }

    },
    methods: {
      loadTop: function () { // 刷新數(shù)據(jù)的操作
        var self = this;
        setTimeout(function () {
          self.list.splice(0, self.list.length);
          var i =0, len=20;
          for (; i< len; i++){
            self.list.push('demo' + i);
          }
          self.$refs.loadmore.onTopLoaded();
        }, 2000);
      },
      loadBottom: function () { // 加載更多數(shù)據(jù)的操作
        //load data

        //this.allLoaded = true;// 若數(shù)據(jù)已全部獲取完畢
        var self = this;
        setTimeout(function () {
          var i =0; len = 10;
          for (; i< len; i++){
            self.list.push('dddd' + i);
          }
          self.$refs.loadmore.onBottomLoaded();
        }, 2000);

      },
      handleTopChange: function (status) {
        this.topStatus = status;
      },
      itemClick: function (data) {
        console.log('item click, msg : ' + data);
      }
    }
  });
</script>

實(shí)現(xiàn)原理解析

布局原理

  • loadmore組件內(nèi)部由三個(gè)slot組成,分別為name=top,name=bottom,default;
  • top用于展示下拉刷新不同狀態(tài)展示的內(nèi)容,初始設(shè)置margin-top為-top的高度來將自己隱藏
  • bottom同top,用于展示上拉加載更多不同狀態(tài)展示的內(nèi)容
  • default填充滾動詳細(xì)內(nèi)容

實(shí)現(xiàn)原理

  • 主要是通過js的touch事件的監(jiān)聽來實(shí)現(xiàn)
  • 在touchmove事件,如果是向下滑動并且滾動的dom的scrollTop為0,那么整個(gè)組件向下偏移(滑動的距離/比值)展示出top solt的內(nèi)容
  • 在touchmove時(shí)間,如果是向上滑動并且滑動到了底部,再繼續(xù)滑動整個(gè)組件向上偏移(滑動的距離/比值)展示出bottom solt的內(nèi)容

源碼解析

組件的template html

 <div class="mint-loadmore">
  <div class="mint-loadmore-content" :class="{ 'is-dropped': topDropped || bottomDropped}" :style="{ 'transform': 'translate3d(0, ' + translate + 'px, 0)' }">
   <slot name="top">
    <div class="mint-loadmore-top" v-if="topMethod">
     <spinner v-if="topStatus === 'loading'" class="mint-loadmore-spinner" :size="20" type="fading-circle"></spinner>
     <span class="mint-loadmore-text">{{ topText }}</span>
    </div>
   </slot>
   <slot></slot>
   <slot name="bottom">
    <div class="mint-loadmore-bottom" v-if="bottomMethod">
     <spinner v-if="bottomStatus === 'loading'" class="mint-loadmore-spinner" :size="20" type="fading-circle"></spinner>
     <span class="mint-loadmore-text">{{ bottomText }}</span>
    </div>
   </slot>
  </div>
 </div>

關(guān)于 上面的spinner標(biāo)簽,是一個(gè)組件,這里不做詳細(xì)介紹。top solt和bottom slot中的內(nèi)容是展示的內(nèi)容,可以通過外部自定義的方式傳入。

其實(shí)它的實(shí)現(xiàn)有一個(gè)很嚴(yán)重的弊端,就是寫死了top solt和bottom slot的高度為50px,而且js中的處理也是使用50px進(jìn)行的邏輯處理。所以并滿足我們開發(fā)中自定義top slot 和bottom slot的需求。

js核心解析

  • props解析:關(guān)于props的解析,可以參考mint-ui的官方文檔
  • data解析
data() {
 return {
  translate: 0, // 此變量決定當(dāng)前組件上下移動,
  scrollEventTarget: null, // 滾動的dom節(jié)點(diǎn)
  containerFilled: false, // 當(dāng)前滾動的內(nèi)容是否填充完整,不完成會調(diào)用 loadmore的回調(diào)函數(shù)
  topText: '', // 下拉刷新,顯示的文本
  topDropped: false, // 記錄當(dāng)前drop狀態(tài),用給組件dom添加is-dropped class(添加回到原點(diǎn)的動畫)
  bottomText: '', // 上拉加載更多 顯示的文本
  bottomDropped: false, // 同topDropped
  bottomReached: false, // 當(dāng)前滾動是否滾動到了底部
  direction: '', // touch-move過程中, 當(dāng)前滑動的方向
  startY: 0, // touch-start 起始的y的坐標(biāo)值
  startScrollTop: 0, // touch-start 起始的滾動dom的 scrollTop
  currentY: 0, // touch-move 過程中的 y的坐標(biāo)
  topStatus: '', // 下拉刷新的狀態(tài): pull(下拉) drop(釋放) loading(正在加載數(shù)據(jù))
  bottomStatus: '' // 上拉加載更多的狀態(tài): 狀態(tài)同上
 };
}

上面的關(guān)于每個(gè)data數(shù)據(jù)的具體作用通過注釋做了詳細(xì)說明。

watch解析

watch: {
 topStatus(val) {
  this.$emit('top-status-change', val);
  switch (val) {
   case 'pull':
    this.topText = this.topPullText;
    break;
   case 'drop':
    this.topText = this.topDropText;
    break;
   case 'loading':
    this.topText = this.topLoadingText;
    break;
  }
 },

 bottomStatus(val) {
  this.$emit('bottom-status-change', val);
  switch (val) {
   case 'pull':
    this.bottomText = this.bottomPullText;
    break;
   case 'drop':
    this.bottomText = this.bottomDropText;
    break;
   case 'loading':
    this.bottomText = this.bottomLoadingText;
    break;
  }
 }
}

上面是組件通過watch監(jiān)聽的兩個(gè)變量,后面我們能看到他們的改變是在touchmove事件中進(jìn)行處理改變的。它的作用是通過它的變化來改變top slot和bottom slot的文本內(nèi)容;

同時(shí)發(fā)出status-change事件給外部使用,因?yàn)榭赡芡獠孔远xtop slot 和bottom slot的內(nèi)容,通過此事件來通知外部當(dāng)前狀態(tài)以便外部進(jìn)行處理。

核心函數(shù)的解析

這里就不將所有的method列出,下面就根據(jù)處理的所以來解析對應(yīng)的method函數(shù)。

首先,入口是在組件mounted生命周期的鉤子回調(diào)中執(zhí)行init函數(shù)

mounted() {
 this.init();// 當(dāng)前 vue component掛載完成之后, 執(zhí)行init()函數(shù)
}

init函數(shù):

init() {
  this.topStatus = 'pull';
  this.bottomStatus = 'pull';
  this.topText = this.topPullText;
  this.scrollEventTarget = this.getScrollEventTarget(this.$el); // 獲取滾動的dom節(jié)點(diǎn)
  if (typeof this.bottomMethod === 'function') {
   this.fillContainer(); // 判斷當(dāng)前滾動內(nèi)容是否填滿,沒有執(zhí)行外部傳入的loadmore回調(diào)函數(shù)加載數(shù)據(jù)
   this.bindTouchEvents(); // 為當(dāng)前組件dom注冊touch事件
  }
  if (typeof this.topMethod === 'function') {
   this.bindTouchEvents();
  }
 },

 fillContainer() {
  if (this.autoFill) {
   this.$nextTick(() => {
    if (this.scrollEventTarget === window) {
     this.containerFilled = this.$el.getBoundingClientRect().bottom >=
      document.documentElement.getBoundingClientRect().bottom;
    } else {
     this.containerFilled = this.$el.getBoundingClientRect().bottom >=
      this.scrollEventTarget.getBoundingClientRect().bottom;
    }
    if (!this.containerFilled) { // 如果沒有填滿內(nèi)容, 執(zhí)行l(wèi)oadmore的操作
     this.bottomStatus = 'loading';
     this.bottomMethod();// 調(diào)用外部的loadmore函數(shù),加載更多數(shù)據(jù)
    }
   });
  }
 }

init函數(shù)主要是初始化狀態(tài)和事件的一些操作,下面著重分析touch事件的回調(diào)函數(shù)的處理。

首先touchstart事件回調(diào)處理函數(shù)

 handleTouchStart(event) {
  this.startY = event.touches[0].clientY; // 手指按下的位置, 用于下面move事件計(jì)算手指移動的距離
  this.startScrollTop = this.getScrollTop(this.scrollEventTarget); // 起始scroll dom的 scrollTop(滾動的距離)
  //下面重置狀態(tài)變量
  this.bottomReached = false;
  if (this.topStatus !== 'loading') {
   this.topStatus = 'pull';
   this.topDropped = false;
  }
  if (this.bottomStatus !== 'loading') {
   this.bottomStatus = 'pull';
   this.bottomDropped = false;
  }
 }

主要是記錄初始位置和重置狀態(tài)變量。

下面繼續(xù)touchmove的回調(diào)處理函數(shù)

 handleTouchMove(event) {
  //確保當(dāng)前touch節(jié)點(diǎn)的y的位置,在當(dāng)前l(fā)oadmore組件的內(nèi)部
  if (this.startY < this.$el.getBoundingClientRect().top && this.startY > this.$el.getBoundingClientRect().bottom) {
   return;
  }
  this.currentY = event.touches[0].clientY;
  let distance = (this.currentY - this.startY) / this.distanceIndex;
  this.direction = distance > 0 ? 'down' : 'up';
  // 下拉刷新,條件(1.外部傳入了刷新的回調(diào)函數(shù) 2.滑動方向是向下的 3.當(dāng)前滾動節(jié)點(diǎn)的scrollTop為0 4.當(dāng)前topStatus不是loading)
  if (typeof this.topMethod === 'function' && this.direction === 'down' &&
   this.getScrollTop(this.scrollEventTarget) === 0 && this.topStatus !== 'loading') {
   event.preventDefault();
   event.stopPropagation();
   //計(jì)算translate(將要平移的距離), 如果當(dāng)前移動的距離大于設(shè)置的最大距離,那么此次這次移動就不起作用了
   if (this.maxDistance > 0) {
    this.translate = distance <= this.maxDistance ? distance - this.startScrollTop : this.translate;
   } else {
    this.translate = distance - this.startScrollTop;
   }
   if (this.translate < 0) {
    this.translate = 0;
   }
   this.topStatus = this.translate >= this.topDistance ? 'drop' : 'pull';// drop: 到達(dá)指定的閾值,可以執(zhí)行刷新操作了
  }

  // 上拉操作, 判斷當(dāng)前scroll dom是否滾動到了底部
  if (this.direction === 'up') {
   this.bottomReached = this.bottomReached || this.checkBottomReached();
  }
  if (typeof this.bottomMethod === 'function' && this.direction === 'up' &&
   this.bottomReached && this.bottomStatus !== 'loading' && !this.bottomAllLoaded) {
   event.preventDefault();
   event.stopPropagation();
   // 判斷的邏輯思路同上
   if (this.maxDistance > 0) {
    this.translate = Math.abs(distance) <= this.maxDistance
     ? this.getScrollTop(this.scrollEventTarget) - this.startScrollTop + distance : this.translate;
   } else {
    this.translate = this.getScrollTop(this.scrollEventTarget) - this.startScrollTop + distance;
   }
   if (this.translate > 0) {
    this.translate = 0;
   }
   this.bottomStatus = -this.translate >= this.bottomDistance ? 'drop' : 'pull';
  }
  this.$emit('translate-change', this.translate);
 }

上面的代碼邏輯挺簡單,注釋也就相對不多。

重點(diǎn)談一下checkBottomReached()函數(shù),用來判斷當(dāng)前scroll dom是否滾動到了底部。

 checkBottomReached() {
  if (this.scrollEventTarget === window) {
   return document.body.scrollTop + document.documentElement.clientHeight >= document.body.scrollHeight;
  } else {
   return this.$el.getBoundingClientRect().bottom <= this.scrollEventTarget.getBoundingClientRect().bottom + 1;
  }
 }

經(jīng)過我的測試,上面的代碼是有問題:

當(dāng)scrollEventTarget是window的條件下,上面的判斷是不對的。因?yàn)閐ocument.body.scrollTop總是比正常值小1,所以用于無法滿足到達(dá)底部的條件;

當(dāng)scrollEventTarget不是window的條件下,上面的判斷條件也不需要在this.scrollEventTarget.getBoundingClientRect().bottom后面加1,但是加1也不會有太大視覺上的影響。

最后來看下moveend事件回調(diào)的處理函數(shù)

 handleTouchEnd() {
  if (this.direction === 'down' && this.getScrollTop(this.scrollEventTarget) === 0 && this.translate > 0) {
   this.topDropped = true; // 為當(dāng)前組件添加 is-dropped class(也就是添加動畫處理)
   if (this.topStatus === 'drop') { // 到達(dá)了loading的狀態(tài)
    this.translate = '50'; // top slot的高度
    this.topStatus = 'loading';
    this.topMethod(); // 執(zhí)行回調(diào)函數(shù)
   } else { // 沒有到達(dá),回調(diào)原點(diǎn)
    this.translate = '0';
    this.topStatus = 'pull';
   }
  }
  // 處理邏輯同上
  if (this.direction === 'up' && this.bottomReached && this.translate < 0) {
   this.bottomDropped = true;
   this.bottomReached = false;
   if (this.bottomStatus === 'drop') {
    this.translate = '-50';
    this.bottomStatus = 'loading';
    this.bottomMethod();
   } else {
    this.translate = '0';
    this.bottomStatus = 'pull';
   }
  }
  this.$emit('translate-change', this.translate);
  this.direction = '';
 }
}

總結(jié)

  1. 下拉刷新和上拉加載更多的實(shí)現(xiàn)原理可以借鑒
  2. getScrollEventTarget()獲取滾動對象,getScrollTop()獲取滾動距離,checkBottomReached()判斷是否滾動到底部;這三種方式可以借鑒
  3. 缺點(diǎn): 寫死了top slot 和 bottom slot的高度,太不靈活;這個(gè)地方可以優(yōu)化

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • element中form組件prop嵌套屬性的問題解決

    element中form組件prop嵌套屬性的問題解決

    本文主要介紹了element中form組件prop嵌套屬性的問題解決,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • vue中this.$http.post()跨域和請求參數(shù)丟失的解決

    vue中this.$http.post()跨域和請求參數(shù)丟失的解決

    這篇文章主要介紹了vue中this.$http.post()跨域和請求參數(shù)丟失的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue語法和標(biāo)簽的入門使用教程

    Vue語法和標(biāo)簽的入門使用教程

    Vue是一套用于構(gòu)建用戶界面的漸進(jìn)式框架,下面這篇文章主要給大家介紹了關(guān)于Vue語法和標(biāo)簽使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • vue調(diào)用原生方法交互解讀

    vue調(diào)用原生方法交互解讀

    這篇文章主要介紹了vue調(diào)用原生方法交互,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue 搭建后臺系統(tǒng)模塊化開發(fā)詳解

    vue 搭建后臺系統(tǒng)模塊化開發(fā)詳解

    這篇文章主要介紹了vue 搭建后臺系統(tǒng)模塊化開發(fā)詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-05-05
  • Vue中的計(jì)算屬性computed傳參方式

    Vue中的計(jì)算屬性computed傳參方式

    這篇文章主要介紹了Vue中的計(jì)算屬性computed傳參方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 在vscode里使用.vue代碼模板的方法

    在vscode里使用.vue代碼模板的方法

    本篇文章主要介紹了在vscode里使用.vue代碼模板的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • 調(diào)用createApp?時(shí)Vue工作過程原理

    調(diào)用createApp?時(shí)Vue工作過程原理

    這篇文章主要為大家介紹了調(diào)用createApp?時(shí)Vue工作過程原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 最基礎(chǔ)的vue.js雙向綁定操作

    最基礎(chǔ)的vue.js雙向綁定操作

    這篇文章主要為大家詳細(xì)介紹了最基礎(chǔ)的vue.js雙向綁定操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • vue2 v-model/v-text 中使用過濾器的方法示例

    vue2 v-model/v-text 中使用過濾器的方法示例

    這篇文章主要介紹了vue2 v-model/v-text 中使用過濾器的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-05-05

最新評論

连云港市| 平江县| 定南县| 沭阳县| 德保县| 城口县| 乃东县| 晴隆县| 宁陵县| 勃利县| 迁安市| 平果县| 安福县| 西贡区| 昭平县| 高邑县| 沈丘县| 社会| 三穗县| 克拉玛依市| 沾益县| 永兴县| 松滋市| 东港市| 孝昌县| 永宁县| 敦化市| 江川县| 乐都县| 迁西县| 和林格尔县| 呼伦贝尔市| 屏山县| 凌源市| 海城市| 任丘市| 射阳县| 安徽省| 龙山县| 井冈山市| 茶陵县|