<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        當(dāng)前位置: 首頁 - 科技 - 知識百科 - 正文

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

        來源:懂視網(wǎng) 責(zé)編:小采 時間:2020-11-27 22:28:08
        文檔

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

        詳解vue mint-ui源碼解析之loadmore組件:本文介紹了vue mint-ui源碼解析之loadmore組件,分享給大家,具體如下: 接入 官方接入文檔mint-ui loadmore文檔 接入使用Example html <div id=app> <mt-loadmore :top-method=loadTop :bottom-me
        推薦度:
        導(dǎo)讀詳解vue mint-ui源碼解析之loadmore組件:本文介紹了vue mint-ui源碼解析之loadmore組件,分享給大家,具體如下: 接入 官方接入文檔mint-ui loadmore文檔 接入使用Example html <div id=app> <mt-loadmore :top-method=loadTop :bottom-me

        本文介紹了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)原理解析

        布局原理

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

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

        組件的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)簽,是一個組件,這里不做詳細(xì)介紹。top solt和bottom slot中的內(nèi)容是展示的內(nèi)容,可以通過外部自定義的方式傳入。

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

        js核心解析

      10. props解析:關(guān)于props的解析,可以參考mint-ui的官方文檔
      11. data解析
      12. 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)于每個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)聽的兩個變量,后面我們能看到他們的改變是在touchmove事件中進(jìn)行處理改變的。它的作用是通過它的變化來改變top slot和bottom slot的文本內(nèi)容;

        同時發(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事件計算手指移動的距離
         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();
         //計算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的高度,太不靈活;這個地方可以優(yōu)化

        聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

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

        詳解vue mint-ui源碼解析之loadmore組件:本文介紹了vue mint-ui源碼解析之loadmore組件,分享給大家,具體如下: 接入 官方接入文檔mint-ui loadmore文檔 接入使用Example html <div id=app> <mt-loadmore :top-method=loadTop :bottom-me
        推薦度:
        標(biāo)簽: VUE min mint
        • 熱門焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top 主站蜘蛛池模板: 久久国产乱子伦免费精品| 99精品全国免费观看视频..| 国产亚洲美女精品久久久| 亚洲综合免费视频| 久久免费精品视频| 中文字幕免费在线视频| 午夜亚洲WWW湿好爽 | 亚洲中文无码a∨在线观看| 亚洲中文字幕无码日韩| 国产在线19禁免费观看国产| 成人午夜大片免费7777| 好吊妞998视频免费观看在线| 妞干网在线免费观看| 国产成人免费爽爽爽视频| 91在线视频免费看| 日本视频免费在线| 午夜亚洲国产成人不卡在线| 国产一区二区三区免费视频| 亚洲av中文无码| 亚洲精品狼友在线播放| 亚洲国产精华液网站w| 亚洲欧洲日本国产| 亚洲AV日韩AV无码污污网站| 免费人成在线观看播放a| 成人免费无码H在线观看不卡| 国产免费久久久久久无码| 玖玖在线免费视频| 最近2019中文字幕mv免费看| 日本高清免费网站| 亚洲国产成人一区二区精品区| 亚洲一区二区三区久久| xxxxx做受大片在线观看免费| 18禁超污无遮挡无码免费网站 | 一本色道久久88亚洲精品综合| 美女被艹免费视频| 日本视频一区在线观看免费| 亚洲av中文无码| 亚洲另类无码专区首页| 久久国产精品国产自线拍免费| 午夜时刻免费入口| 久久亚洲私人国产精品|