vue loadmore 組件滑動加載更多源碼解析
上一篇講到在項目中使用上拉加載更多組件,但是由于實際項目開發(fā)中由于需求變更或者說在webview中上拉加載有些機型在上拉時候會把webview也一起上拉導(dǎo)致上拉加載不靈敏等問題,我們有時候也會換成滑動到底部自動加載的功能。
既然都是加載更多,很多代碼思想勢必相似,主要區(qū)別在于上拉和滑動到底部這個操作上,所以,我們需要注意:
上拉加載是point指針touch觸摸事件,現(xiàn)在因為是滑動加載,需要添加scroll事件去監(jiān)聽然后執(zhí)行相應(yīng)回調(diào)
上拉加載主要計算觸摸滾動距離,滑動加載主要計算container底部和視窗上邊緣的距離
事件綁定改成:
mounted() { ··· this.dom.addEventListener('scroll', this.scroll, false) ··· }, beforeDestroy() { ··· this.dom.removeEventListener('scroll', this.scroll, false) ··· },
事件回調(diào)改為:
/** * 滾動鉤子 */ scroll() { const viewHeight = global.innerHeight let parentNode if (this.container !== global) { parentNode = this.$el } else { parentNode = this.$el.parentNode } if (parentNode) { // 獲取Vue實例使用的根 DOM 元素相對于視口的位置 const rect = parentNode.getBoundingClientRect() // this.distance 離底部多少距離開始加載 // 如果此元素底邊距離視口頂部的距離小于視口高度加上distance之和,就加載下一頁 if ((rect.bottom <= viewHeight + this.distance) && this.loadable && !this.loading) { this.load() } } },
源碼如下:
<template> <div class="loadmore" ref="loadmore"> <div class="loadmore__body"> <slot></slot> </div> <div class="loadmore__footer"> <span v-if="loading"> <i class="tc-loading"></i> <span>正在加載</span> </span> <span v-else-if="loadable">加載更多</span> <span v-else>沒有更多了</span> </div> </div> </template> <script type="text/babel"> import axios from 'axios' const CancelToken = axios.CancelToken export default { data() { return { /** * 總頁數(shù)(由服務(wù)端返回) * @type {number} */ count: 0, /** * 是否正在拖拽中 * @type {boolean} */ dragging: false, /** * 已加載次數(shù) * @type {number} */ times: 0, /** * 已開始記載 * @type {boolean} */ started: false, /** * 正在加載中 * @type {boolean} */ loading: false, dom: null, } }, props: { /** * 初始化后自動開始加載數(shù)據(jù) */ autoload: { type: Boolean, default: true, }, /** * 離組件最近的可滾動父級元素(用于監(jiān)聽事件及獲取滾動條位置) */ container: { // Selector or Element default: () => (global), }, /** * Axios請求參數(shù)配置對象 * {@link https://github.com/mzabriskie/axios#request-config} */ options: { type: Object, default: null, }, /** * 起始頁碼 */ page: { type: Number, default: 1, }, /** * 每頁加載數(shù)據(jù)條數(shù) */ rows: { type: Number, default: 10, }, /** * 數(shù)據(jù)加載請求地址 */ url: { type: String, default: '', }, /** * 距離底部多遠(yuǎn)加載 */ distance: { type: Number, default: 200, }, }, computed: { /** * 是否可以加載 * @returns {boolean} 是與否 */ loadable() { return !this.started || (this.page + this.times) <= this.count }, }, mounted() { if (this.container !== global) { this.dom = document.querySelector(this.container) } else { this.dom = this.container } if (!this.dom) { return } this.dom.addEventListener('scroll', this.scroll, false) if (this.autoload && !this.loading) { this.load() } }, // eslint-disable-next-line beforeDestroy() { if (this.dom) { this.dom.removeEventListener('scroll', this.scroll, false) } }, methods: { /** * 滾動鉤子 */ scroll() { const viewHeight = global.innerHeight let parentNode if (this.container !== global) { parentNode = this.$el } else { parentNode = this.$el.parentNode } if (parentNode) { const rect = parentNode.getBoundingClientRect() if ((rect.bottom <= viewHeight + this.distance) && this.loadable && !this.loading) { this.load() } } }, /** * 加載一組數(shù)據(jù)的方法 */ load() { if (this.loading) { return } this.started = true this.loading = true const params = { currentPage: this.page + this.times, pageSize: this.rows, } const options = Object.assign({}, this.options, { url: this.url, cancelToken: new CancelToken((cancel) => { this.cancel = cancel }), }) if (String(options.method).toUpperCase() === 'POST') { options.data = Object.assign({}, options.data, params) } else { options.params = Object.assign({}, options.params, params) } this.$axios.request(options).then((res) => { const data = res.result this.times += 1 this.loading = false this.count = data.pageCount this.$emit('success', data.list) this.$emit('complete') }).catch((e) => { this.loading = false this.$emit('error', e) this.$emit('complete') }) }, /** * 重置加載相關(guān)變量 */ reset() { this.count = 0 this.times = 0 this.started = false this.loading = false }, /** *重新開始加載 */ restart() { this.reset() this.load() }, }, } </script>
以上所述是小編給大家介紹的vue loadmore 組件滑動加載更多源碼解析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
VueJs中的shallowRef與shallowReactive函數(shù)使用比較
這篇文章主要為大家介紹了VueJs中的shallowRef與shallowReactive函數(shù)的使用比較解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04vue用vis插件如何實現(xiàn)網(wǎng)絡(luò)拓?fù)鋱D
這篇文章主要介紹了vue用vis插件如何實現(xiàn)網(wǎng)絡(luò)拓?fù)鋱D,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10通過debug搞清楚.vue文件如何變成.js文件(案例詳解)
這篇文章主要介紹了通過debug搞清楚.vue文件如何變成.js文件,本文以@vitejs/plugin-vue舉例,通過debug的方式帶你一步一步的搞清楚vue文件是如何編譯為js文件的,需要的朋友可以參考下2024-07-07Vue項目中數(shù)據(jù)的深度監(jiān)聽或?qū)ο髮傩缘谋O(jiān)聽實例
這篇文章主要介紹了Vue項目中數(shù)據(jù)的深度監(jiān)聽或?qū)ο髮傩缘谋O(jiān)聽實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07Vue生命周期activated之返回上一頁不重新請求數(shù)據(jù)操作
這篇文章主要介紹了Vue生命周期activated之返回上一頁不重新請求數(shù)據(jù)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07Vue.js仿Metronic高級表格(一)靜態(tài)設(shè)計
這篇文章主要為大家詳細(xì)介紹了Vue.js仿Metronic高級表格的靜態(tài)設(shè)計,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04