Heim >Web-Frontend >js-Tutorial >Analyse der Loadmore-Komponente in Vue Mint-UI
In diesem Artikel wird hauptsächlich die Loadmore-Komponente der Vue-Mint-UI-Quellcode-Analyse vorgestellt. Jetzt werde ich sie mit Ihnen teilen und Ihnen eine Referenz geben. Folgen wir dem Herausgeber und schauen wir uns das an. Ich hoffe, es kann allen helfen.
Zugriff
Offizielles Zugriffsdokument Mint-UI Loadmore-Dokument
Zugriff anhand eines Beispiels
HTML
<p id="app"> <mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :max-distance="150" @top-status-change="handleTopChange" ref="loadmore"> <p 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> </p> <ul class="scroll-wrapper"> <li v-for="item in list" @click="itemClick(item)">{{ item }}</li> </ul> </mt-loadmore> </p>
css
<link rel="stylesheet" href="https://unpkg.com/mint-ui/lib/style.css" 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 () { // 刷新数据的操作 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 () { // 加载更多数据的操作 //load data //this.allLoaded = true;// 若数据已全部获取完毕 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>
Analyse des Implementierungsprinzips
Layoutprinzip
Die Loadmore-Komponente besteht intern aus drei Slots mit dem Namen = oben, Name = unten, Standard;
top wird verwendet, um den in verschiedenen Stadien der Pulldown-Aktualisierung angezeigten Inhalt anzuzeigen. Der Rand oben wird zunächst auf die Höhe von -top eingestellt, um sich selbst auszublenden
Unten ist dasselbe wie oben und wird zum Anzeigen des Pull-up-Ladens verwendet, um mehr Inhalte in verschiedenen Zuständen anzuzeigen
Standardmäßig werden Scrolldetails ausgefüllt
Implementierungsprinzip
Es wird hauptsächlich durch die Überwachung des Berührungsereignisses von js implementiert
Wenn es im Touchmove-Ereignis nach unten gleitet und der scrollTop-Wert des Scroll-Doms 0 ist, wird die gesamte Komponente nach unten versetzt (Gleitweg/Verhältnis), um den Inhalt des oberen Solts anzuzeigen
Wenn Sie zum Touchmove-Zeitpunkt nach oben und nach unten gleiten, schieben Sie dann die gesamte Komponente weiter nach oben, um einen Versatz (Gleitweg/Verhältnis) zu erreichen, um den Inhalt des unteren Verkaufs anzuzeigen
Quellcode-Analyse
Vorlage-HTML der Komponente
<p class="mint-loadmore"> <p class="mint-loadmore-content" :class="{ 'is-dropped': topDropped || bottomDropped}" :style="{ 'transform': 'translate3d(0, ' + translate + 'px, 0)' }"> <slot name="top"> <p 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> </p> </slot> <slot></slot> <slot name="bottom"> <p 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> </p> </slot> </p> </p>
Bezüglich des Spinners Tag oben, es ist eine Komponente und wird hier nicht im Detail vorgestellt. Der Inhalt im oberen und unteren Bereich ist der angezeigte Inhalt und kann durch externe Anpassung übergeben werden.
Tatsächlich weist seine Implementierung einen sehr gravierenden Nachteil auf, nämlich dass die Höhe des oberen Lots und des unteren Schlitzes auf 50 Pixel programmiert ist und die Verarbeitung in js auch 50 Pixel für die logische Verarbeitung verwendet. Daher erfüllt es die Anforderungen der individuellen Anpassung des oberen und unteren Schlitzes in unserer Entwicklung.
JS-Kernanalyse
Requisitenanalyse: Informationen zur Analyse von Requisiten finden Sie in der offiziellen Dokumentation von mint-ui
Datenanalyse
data() { return { translate: 0, // 此变量决定当前组件上下移动, scrollEventTarget: null, // 滚动的dom节点 containerFilled: false, // 当前滚动的内容是否填充完整,不完成会调用 loadmore的回调函数 topText: '', // 下拉刷新,显示的文本 topDropped: false, // 记录当前drop状态,用给组件dom添加is-dropped class(添加回到原点的动画) bottomText: '', // 上拉加载更多 显示的文本 bottomDropped: false, // 同topDropped bottomReached: false, // 当前滚动是否滚动到了底部 direction: '', // touch-move过程中, 当前滑动的方向 startY: 0, // touch-start 起始的y的坐标值 startScrollTop: 0, // touch-start 起始的滚动dom的 scrollTop currentY: 0, // touch-move 过程中的 y的坐标 topStatus: '', // 下拉刷新的状态: pull(下拉) drop(释放) loading(正在加载数据) bottomStatus: '' // 上拉加载更多的状态: 状态同上 }; }
Die oben genannten spezifischen Funktionen der einzelnen Daten werden durch Kommentare ausführlich erläutert.
Überwachungsanalyse
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; } } }
Die oben genannten sind die beiden Variablen, die die Komponente durch Überwachung überwacht. Später können wir sehen, dass sich ihre Änderungen im Touchmove befinden Ereignisverarbeitungsänderungen werden vorgenommen. Seine Funktion besteht darin, den Textinhalt des oberen und unteren Slots durch seine Änderungen zu ändern.
Gleichzeitig wird das Statusänderungsereignis zur externen Verwendung ausgegeben, da der Inhalt des oberen Slots geändert wird Steckplatz und unterer Steckplatz können extern angepasst werden. Verwenden Sie dieses Ereignis, um den aktuellen Status für die externe Verarbeitung nach außen zu benachrichtigen.
Analyse der Kernfunktionen
Ich werde hier nicht alle Methoden auflisten die Verarbeitungsmethodenfunktion.
Der Einstiegspunkt besteht zunächst darin, die Init-Funktion im Hook-Callback des bereitgestellten Lebenszyklus der Komponente
mounted() { this.init();// 当前 vue component挂载完成之后, 执行init()函数 }
Init-Funktion auszuführen :
init() { this.topStatus = 'pull'; this.bottomStatus = 'pull'; this.topText = this.topPullText; this.scrollEventTarget = this.getScrollEventTarget(this.$el); // 获取滚动的dom节点 if (typeof this.bottomMethod === 'function') { this.fillContainer(); // 判断当前滚动内容是否填满,没有执行外部传入的loadmore回调函数加载数据 this.bindTouchEvents(); // 为当前组件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) { // 如果没有填满内容, 执行loadmore的操作 this.bottomStatus = 'loading'; this.bottomMethod();// 调用外部的loadmore函数,加载更多数据 } }); } }
Die Init-Funktion führt hauptsächlich einige Vorgänge zum Initialisierungsstatus und zu Ereignissen aus. Im Folgenden liegt der Schwerpunkt auf der Verarbeitung der Rückruffunktion des Berührungsereignisses.
Erstens wird die Touchstart-Ereignis-Callback-Handler-Funktion
handleTouchStart(event) { this.startY = event.touches[0].clientY; // 手指按下的位置, 用于下面move事件计算手指移动的距离 this.startScrollTop = this.getScrollTop(this.scrollEventTarget); // 起始scroll dom的 scrollTop(滚动的距离) //下面重置状态变量 this.bottomReached = false; if (this.topStatus !== 'loading') { this.topStatus = 'pull'; this.topDropped = false; } if (this.bottomStatus !== 'loading') { this.bottomStatus = 'pull'; this.bottomDropped = false; } }
hauptsächlich zum Aufzeichnen der Anfangsposition und zum Zurücksetzen von Statusvariablen verwendet.
Im Folgenden wird mit der Touchmove-Rückrufverarbeitungsfunktion fortgefahren
handleTouchMove(event) { //确保当前touch节点的y的位置,在当前loadmore组件的内部 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.外部传入了刷新的回调函数 2.滑动方向是向下的 3.当前滚动节点的scrollTop为0 4.当前topStatus不是loading) if (typeof this.topMethod === 'function' && this.direction === 'down' && this.getScrollTop(this.scrollEventTarget) === 0 && this.topStatus !== 'loading') { event.preventDefault(); event.stopPropagation(); //计算translate(将要平移的距离), 如果当前移动的距离大于设置的最大距离,那么此次这次移动就不起作用了 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: 到达指定的阈值,可以执行刷新操作了 } // 上拉操作, 判断当前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); }
Die obige Codelogik ist recht einfach und es gibt relativ wenige Kommentare .
Konzentrieren Sie sich auf die Funktion checkBottomReached(), mit der ermittelt wird, ob der aktuelle Scroll-Dom nach unten gescrollt wurde.
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; } }
Nach meinen Tests gibt es ein Problem mit dem obigen Code:
Wenn scrollEventTarget ein Fenster ist, wird das obige Urteil gefällt nicht richtig. Da document.body.scrollTop immer um 1 kleiner als der Normalwert ist, kann es die Bedingung, den unteren Rand zu erreichen, nicht erfüllen.
Wenn scrollEventTarget kein Fenster ist, muss die obige Beurteilungsbedingung nicht erfüllt sein Dies Fügen Sie 1 nach .scrollEventTarget.getBoundingClientRect().bottom hinzu, aber das Hinzufügen von 1 hat keine große visuelle Wirkung.
Schauen wir uns zum Schluss die Handlerfunktion des Moveend-Ereignisrückrufs an
handleTouchEnd() { if (this.direction === 'down' && this.getScrollTop(this.scrollEventTarget) === 0 && this.translate > 0) { this.topDropped = true; // 为当前组件添加 is-dropped class(也就是添加动画处理) if (this.topStatus === 'drop') { // 到达了loading的状态 this.translate = '50'; // top slot的高度 this.topStatus = 'loading'; this.topMethod(); // 执行回调函数 } else { // 没有到达,回调原点 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 = ''; } }
Zusammenfassung
Weitere Implementierungsprinzipien der Pulldown-Aktualisierung und des Pullup-Ladens können von
getScrollEventTarget() zum Abrufen des Bildlaufobjekts getScrollTop() gelernt werden Ermitteln Sie den Bildlaufabstand und prüfen Sie mit checkBottomReached(), ob diese drei Methoden als Referenz verwendet werden können.
Nachteile: Die Höhe des oberen und unteren Schlitzes ist schwierig -codiert, was zu unflexibel ist. Dieser Ort kann optimiert werden auf Mint-UI
vue Mint-UI Nachahmung Taobao und JD.com Lieferadresse vierstufige Verknüpfung
Das obige ist der detaillierte Inhalt vonAnalyse der Loadmore-Komponente in Vue Mint-UI. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!