vue loadmore組件上拉加載更多功能示例代碼
最近在做移動端h5頁面,所以分頁什么的就不能按照傳統(tǒng)pc端的分頁器的思維去做了,這么小的屏幕去點(diǎn)擊也不太方便一般來講移動端都是上拉加載更多,符合正常使用習(xí)慣。
首先簡單寫一下模板部分的html代碼,,很簡單清晰的邏輯:
<template> <div class="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>
然后就是業(yè)務(wù)部分了
在動手寫組件之前,先理清需求:
加載頁面 -> 滑到底部 -> 上拉一定距離 -> 加載第二頁 -> 繼續(xù)前面步驟 -> 沒有更多
這是一個用戶交互邏輯,而我們需要將其映射為代碼邏輯:
首屏自動加載第一頁 -> 滑動到底部&&按下時候滑動距離Y軸有一定偏移量 -> 請求后端加載第二頁 -> 根據(jù)返回字段判斷是否還有下一頁
有了代碼邏輯,主干就出來了,加載和判斷由事件來控制,而又作為一個vue組件,我們需要配合vue生命周期來掛載事件和銷毀事件
export default { mounted() { // 確定容器 // 容器綁定事件 }, beforeDestory() { // 解綁事件 }, }
如果沒有解綁的話,每次你加載組件,就會綁定一次事件…
然后我們需要一些核心事件回調(diào)方法來在合適的時間加載數(shù)據(jù)渲染頁面, 回想一下,第一我們需要http獲取數(shù)據(jù)的load函數(shù),然后我們需要三個綁定事件的回調(diào)函數(shù)pointDown(), pointMove(), pointUp(),分別對應(yīng)用戶按下、移動、彈起手指操作:
export default { ··· methods:{ /** * 加載一組數(shù)據(jù)的方法 */ load() { // 設(shè)置options this.$axios.request(options).then((res) => { // 獲取數(shù)據(jù)后的處理 }).catch((e) => { // 異常處理 }) }, /** * 鼠標(biāo)按下事件處理函數(shù) * @param {Object} e - 事件對象 */ pointerdown(e) { // 獲取按下的位置 this.pageY = e.changedTouches ? e.changedTouches[0].pageY : e.pageY }, /** * 鼠標(biāo)移動事件處理函數(shù) * @param {Object} e - 事件對象 */ pointermove(e) { const container = this.$container const pageY = e.changedTouches ? e.changedTouches[0].pageY : e.pageY const moveY = pageY - this.pageY // 如果已經(jīng)向下滾動到頁面最底部 if (moveY < 0 && (container.scrollTop + Math.min( global.innerHeight, container.clientHeight, )) >= container.scrollHeight) { // 阻止原生的上拉拖動會露出頁面底部空白區(qū)域的行為(主要針對iOS版微信) e.preventDefault() // 如果上拉距離超過50像素,則加載下一頁 if (moveY < -50) { this.pageY = pageY this.load() } } }, /** * 鼠標(biāo)松開事件處理函數(shù) */ pointerup() { // 這邊就是取消拖動狀態(tài),需要注意在拖動過程中不要再次觸發(fā)一些事件回調(diào),否側(cè)亂套 this.dragging = false }, }, ··· }
基本上主干已經(jīng)算完工了,一些props傳入或者一些邏輯控制細(xì)節(jié)需要再額外添加,貼出整個組件的源碼:
<template> <div class="loadmore"> <!-- <div class="loadmore__header"></div> --> <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, } }, props: { /** * 初始化后自動開始加載數(shù)據(jù) */ autoload: { type: Boolean, default: true, }, /** * 離組件最近的可滾動父級元素(用于監(jiān)聽事件及獲取滾動條位置) */ container: { // Selector or Element default: 'body', }, /** * 禁用組件 */ disabled: { type: Boolean, default: false, }, /** * 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: '', }, }, computed: { /** * 是否可以加載 * @returns {boolean} 是與否 */ loadable() { return !this.disabled && (!this.started || (this.page + this.times) <= this.count) }, }, mounted() { let container = this.container if (container) { if (typeof container === 'string') { container = document.querySelector(container) } else if (!container.querySelector) { container = document.body } } if (!container) { container = document.body } this.$container = container this.onPointerDown = this.pointerdown.bind(this) this.onPointerMove = this.pointermove.bind(this) this.onPointerUp = this.pointerup.bind(this) if (global.PointerEvent) { container.addEventListener('pointerdown', this.onPointerDown, false) container.addEventListener('pointermove', this.onPointerMove, false) container.addEventListener('pointerup', this.onPointerUp, false) container.addEventListener('pointercancel', this.onPointerUp, false) } else { container.addEventListener('touchstart', this.onPointerDown, false) container.addEventListener('touchmove', this.onPointerMove, false) container.addEventListener('touchend', this.onPointerUp, false) container.addEventListener('touchcancel', this.onPointerUp, false) container.addEventListener('mousedown', this.onPointerDown, false) container.addEventListener('mousemove', this.onPointerMove, false) container.addEventListener('mouseup', this.onPointerUp, false) } if (this.autoload) { this.load() } }, // eslint-disable-next-line beforeDestroy() { const container = this.$container if (global.PointerEvent) { container.removeEventListener('pointerdown', this.onPointerDown, false) container.removeEventListener('pointermove', this.onPointerMove, false) container.removeEventListener('pointerup', this.onPointerUp, false) container.removeEventListener('pointercancel', this.onPointerUp, false) } else { container.removeEventListener('touchstart', this.onPointerDown, false) container.removeEventListener('touchmove', this.onPointerMove, false) container.removeEventListener('touchend', this.onPointerUp, false) container.removeEventListener('touchcancel', this.onPointerUp, false) container.removeEventListener('mousedown', this.onPointerDown, false) container.removeEventListener('mousemove', this.onPointerMove, false) container.removeEventListener('mouseup', this.onPointerUp, false) } if (this.loading && this.cancel) { this.cancel() } }, methods: { /** * 加載一組數(shù)據(jù)的方法 */ load() { if (this.disabled || 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() }, /** * 鼠標(biāo)按下事件處理函數(shù) * @param {Object} e - 事件對象 */ pointerdown(e) { if (this.disabled || !this.loadable || this.loading) { return } this.dragging = true this.pageY = e.changedTouches ? e.changedTouches[0].pageY : e.pageY }, /** * 鼠標(biāo)移動事件處理函數(shù) * @param {Object} e - 事件對象 */ pointermove(e) { if (!this.dragging) { return } const container = this.$container const pageY = e.changedTouches ? e.changedTouches[0].pageY : e.pageY const moveY = pageY - this.pageY // 如果已經(jīng)向下滾動到頁面最底部 if (moveY < 0 && (container.scrollTop + Math.min( global.innerHeight, container.clientHeight, )) >= container.scrollHeight) { // 阻止原生的上拉拖動會露出頁面底部空白區(qū)域的行為(主要針對iOS版微信) e.preventDefault() // 如果上拉距離超過50像素,則加載下一頁 if (moveY < -50) { this.pageY = pageY this.load() } } }, /** * 鼠標(biāo)松開事件處理函數(shù) */ pointerup() { this.dragging = false }, }, } </script>
以上所述是小編給大家介紹的vue loadmore組件上拉加載更多功能示例代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
- 基于vue封裝下拉刷新上拉加載組件
- vue瀑布流組件實(shí)現(xiàn)上拉加載更多
- vue實(shí)現(xiàn)的上拉加載更多數(shù)據(jù)/分頁功能示例
- vueScroll實(shí)現(xiàn)移動端下拉刷新、上拉加載
- vue插件mescroll.js實(shí)現(xiàn)移動端上拉加載和下拉刷新
- vue移動端下拉刷新和上拉加載的實(shí)現(xiàn)代碼
- vue2.0 移動端實(shí)現(xiàn)下拉刷新和上拉加載更多的示例
- 基于vue2實(shí)現(xiàn)上拉加載功能
- vue.js移動端app之上拉加載以及下拉刷新實(shí)戰(zhàn)
- vue基于vant實(shí)現(xiàn)上拉加載下拉刷新的示例代碼
相關(guān)文章
vue 封裝導(dǎo)出Excel數(shù)據(jù)的公共函數(shù)的方法
本文主要介紹了vue 封裝導(dǎo)出Excel數(shù)據(jù)的公共函數(shù),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09vue根據(jù)權(quán)限動態(tài)渲染按鈕、組件等的函數(shù)式組件實(shí)現(xiàn)
這篇文章主要介紹了vue根據(jù)權(quán)限動態(tài)渲染按鈕、組件等的函數(shù)式組件實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望杜大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11vuex實(shí)現(xiàn)數(shù)據(jù)持久化的兩種方案
這兩天在做vue項(xiàng)目存儲個人信息的時候,遇到了頁面刷新后個人信息數(shù)據(jù)丟失的問題,在查閱資料后,我得出兩種解決數(shù)據(jù)丟失,使用數(shù)據(jù)持久化的方法,感興趣的小伙伴跟著小編一起來看看吧2023-08-08vue 路由懶加載中給 Webpack Chunks 命名的方法
這篇文章主要介紹了在 vue 路由懶加載中給 Webpack Chunks 命名的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04