基于vue2實(shí)現(xiàn)上拉加載功能
本文實(shí)例為大家分享了vue2實(shí)現(xiàn)上拉加載展示的具體代碼,供大家參考,具體內(nèi)容如下
因?yàn)槲覀冺?xiàng)目中,還用了swiper。很多都是滑動(dòng)切換的,但是又得上拉加載,所以導(dǎo)致,很多UI框架,我們用了,都有不同的bug出現(xiàn),沒(méi)辦法,最后寫(xiě)了一個(gè)。代碼如下(這個(gè)因?yàn)楹芏嗟胤綍?huì)用,所以建議放在components/common下面):
<template> <div class="loadmore"> <slot></slot> <slot name="bottom"> </slot> </div> </template> <style> .loadmore{ width:100%; } </style> <script> export default { name: 'loadmore', props: { maxDistance: { type: Number, default: 0 }, autoFill: { type: Boolean, default: true }, distanceIndex: { type: Number, default: 2 }, bottomPullText: { type: String, default: '上拉刷新' }, bottomDropText: { type: String, default: '釋放更新' }, bottomLoadingText: { type: String, default: '加載中...' }, bottomDistance: { type: Number, default: 70 }, bottomMethod: { type: Function }, bottomAllLoaded: { type: Boolean, default: false }, }, data() { return { // 最下面出現(xiàn)的div的位移 translate: 0, // 選擇滾動(dòng)事件的監(jiān)聽(tīng)對(duì)象 scrollEventTarget: null, containerFilled: false, bottomText: '', // class類(lèi)名 bottomDropped: false, // 獲取監(jiān)聽(tīng)滾動(dòng)元素的scrollTop bottomReached: false, // 滑動(dòng)的方向 down---向下互動(dòng);up---向上滑動(dòng) direction: '', startY: 0, startScrollTop: 0, // 實(shí)時(shí)的clientY位置 currentY: 0, topStatus: '', // 上拉加載的狀態(tài) '' pull: 上拉中 bottomStatus: '', }; }, watch: { // 改變當(dāng)前加載在狀態(tài) 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; } } }, methods: { onBottomLoaded() { this.bottomStatus = 'pull'; this.bottomDropped = false; this.$nextTick(() => { if (this.scrollEventTarget === window) { document.body.scrollTop += 50; } else { this.scrollEventTarget.scrollTop += 50; } this.translate = 0; }); // 注釋 if (!this.bottomAllLoaded && !this.containerFilled) { this.fillContainer(); } }, getScrollEventTarget(element) { let currentNode = element; while (currentNode && currentNode.tagName !== 'HTML' && currentNode.tagName !== 'BODY' && currentNode.nodeType === 1) { let overflowY = document.defaultView.getComputedStyle(currentNode).overflowY; if (overflowY === 'scroll' || overflowY === 'auto') { return currentNode; } currentNode = currentNode.parentNode; } return window; }, // 獲取scrollTop getScrollTop(element) { if (element === window) { return Math.max(window.pageYOffset || 0, document.documentElement.scrollTop); } else { return element.scrollTop; } }, bindTouchEvents() { this.$el.addEventListener('touchstart', this.handleTouchStart); this.$el.addEventListener('touchmove', this.handleTouchMove); this.$el.addEventListener('touchend', this.handleTouchEnd); }, init() { this.bottomStatus = 'pull'; // 選擇滾動(dòng)事件的監(jiān)聽(tīng)對(duì)象 this.scrollEventTarget = this.getScrollEventTarget(this.$el); if (typeof this.bottomMethod === 'function') { // autoFill 屬性的實(shí)現(xiàn) 注釋 this.fillContainer(); // 綁定滑動(dòng)事件 this.bindTouchEvents(); } }, // autoFill 屬性的實(shí)現(xiàn) 注釋 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) { this.bottomStatus = 'loading'; this.bottomMethod(); } }); } }, // 獲取監(jiān)聽(tīng)滾動(dòng)元素的scrollTop checkBottomReached() { if (this.scrollEventTarget === window) { return document.body.scrollTop + document.documentElement.clientHeight >= document.body.scrollHeight; } else { // getBoundingClientRect用于獲得頁(yè)面中某個(gè)元素的左,上,右和下分別相對(duì)瀏覽器視窗的位置。 right是指元素右邊界距窗口最左邊的距離,bottom是指元素下邊界距窗口最上面的距離。 return this.$el.getBoundingClientRect().bottom <= this.scrollEventTarget.getBoundingClientRect().bottom + 1; } }, // ontouchstart 事件 handleTouchStart(event) { // 獲取起點(diǎn)的y坐標(biāo) this.startY = event.touches[0].clientY; this.startScrollTop = this.getScrollTop(this.scrollEventTarget); this.bottomReached = false; if (this.bottomStatus !== 'loading') { this.bottomStatus = 'pull'; this.bottomDropped = false; } }, // ontouchmove事件 handleTouchMove(event) { if (this.startY < this.$el.getBoundingClientRect().top && this.startY > this.$el.getBoundingClientRect().bottom) { // 沒(méi)有在需要滾動(dòng)的范圍內(nèi)滾動(dòng),不再監(jiān)聽(tīng)scroll return; } // 實(shí)時(shí)的clientY位置 this.currentY = event.touches[0].clientY; // distance 移動(dòng)位置和開(kāi)始位置的差值 distanceIndex--- let distance = (this.currentY - this.startY) / this.distanceIndex; // 根據(jù) distance 判斷滑動(dòng)的方向 并賦予變量 direction down---向下互動(dòng);up---向上滑動(dòng) this.direction = distance > 0 ? 'down' : 'up'; if (this.direction === 'up') { // 獲取監(jiān)聽(tīng)滾動(dòng)元素的scrollTop this.bottomReached = this.bottomReached || this.checkBottomReached(); } if (typeof this.bottomMethod === 'function' && this.direction === 'up' && this.bottomReached && this.bottomStatus !== 'loading' && !this.bottomAllLoaded) { // 有加載函數(shù),是向上拉,有滾動(dòng)距離,不是正在加載ajax,沒(méi)有加載到最后一頁(yè) 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'; } }, // ontouchend事件 handleTouchEnd() { 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.direction = ''; } }, mounted() { this.init(); } }; </script>
然后哪個(gè)頁(yè)面需要,在哪個(gè)頁(yè)面導(dǎo)入即可:import LoadMore from './../common/loadmore.vue';在需要引入他的頁(yè)面寫(xiě)法如下:
<template> <section class="finan"> <!-- 上拉加載更多 --> <load-more :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :bottomPullText='bottomText' :auto-fill="false" @bottom-status-change="handleBottomChange" ref="loadmore"> <div> 這里寫(xiě)你需要的另外的模塊 </div> <div v-show="loading" slot="bottom" class="loading"> 這個(gè)div是為讓上拉加載的時(shí)候顯示一張加載的gif圖 <img src="./../../assets/main/uploading.gif"> </div> </load-more> </section> </template>
然后在此頁(yè)面的data里和methods設(shè)置如下:
export default { name: 'FinancialGroup', props:{ }, data () { return { // 上拉加載數(shù)據(jù) scrollHeight: 0, scrollTop: 0, containerHeight: 0, loading: false, allLoaded: false, bottomText: '上拉加載更多...', bottomStatus: '', pageNo: 1, totalCount: '', } }, methods: { /* 下拉加載 */ _scroll: function(ev) { ev = ev || event; this.scrollHeight = this.$refs.innerScroll.scrollHeight; this.scrollTop = this.$refs.innerScroll.scrollTop; this.containerHeight = this.$refs.innerScroll.offsetHeight; }, loadBottom: function() { this.loading = true; this.pageNo += 1; // 每次更迭加載的頁(yè)數(shù) if (this.pageNo == this.totalGetCount) { // 當(dāng)allLoaded = true時(shí)上拉加載停止 this.loading = false; this.allLoaded = true; } api.commonApi(后臺(tái)接口,請(qǐng)求參數(shù)) 這個(gè)api是封裝的axios有不懂的可以看vue2+vuex+axios那篇文章 .then(res => { setTimeout(() => { 要使用的后臺(tái)返回的數(shù)據(jù)寫(xiě)在setTimeout里面 this.$nextTick(() => { this.loading = false; }) }, 1000) }); }, handleBottomChange(status) { this.bottomStatus = status; }, }
這樣就完成了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
把vue-router和express項(xiàng)目部署到服務(wù)器的方法
下面小編就為大家分享一篇把vue-router和express項(xiàng)目部署到服務(wù)器的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02element-plus日歷(Calendar)動(dòng)態(tài)渲染以及避坑指南
這篇文章主要給大家介紹了關(guān)于element-plus日歷(Calendar)動(dòng)態(tài)渲染以及避坑指南的相關(guān)資料,這是最近幫一個(gè)后端朋友處理一個(gè)前端問(wèn)題,elementUI中calendar日歷組件內(nèi)容進(jìn)行自定義顯示,實(shí)現(xiàn)類(lèi)似通知事項(xiàng)的日歷效果,需要的朋友可以參考下2023-08-08VueJs使用Amaze ui調(diào)整列表和內(nèi)容頁(yè)面
這篇文章主要介紹了VueJs 填坑日記之使用Amaze ui調(diào)整列表和內(nèi)容頁(yè)面,需要的朋友可以參考下2017-11-11ElementUI組件Dialog彈窗再次打開(kāi)表單仍顯示上次數(shù)據(jù)的問(wèn)題
這篇文章主要介紹了ElementUI組件Dialog彈窗再次打開(kāi)表單仍顯示上次數(shù)據(jù)的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04尤雨溪開(kāi)發(fā)vue?dev?server理解vite原理
這篇文章主要為大家介紹了尤雨溪開(kāi)發(fā)的玩具vite,vue-dev-server來(lái)理解vite原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07vue3無(wú)config文件夾打包后頁(yè)面空白問(wèn)題及解決
這篇文章主要介紹了vue3無(wú)config文件夾打包后頁(yè)面空白問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05vue結(jié)合v-for和input實(shí)現(xiàn)多選列表checkbox功能
在Vue中,可通過(guò)v-for指令和v-model實(shí)現(xiàn)多選列表功能,首先,使用v-for指令遍歷數(shù)組生成列表項(xiàng),每個(gè)列表項(xiàng)包含一個(gè)復(fù)選框,復(fù)選框的v-model綁定到一個(gè)數(shù)組變量,用于存儲(chǔ)選中的值,感興趣的朋友跟隨小編一起看看吧2024-09-09解決vue動(dòng)態(tài)為數(shù)據(jù)添加新屬性遇到的問(wèn)題
今天小編就為大家分享一篇解決vue動(dòng)態(tài)為數(shù)據(jù)添加新屬性遇到的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09