vue + element-ui的分頁問題實(shí)現(xiàn)
背景介紹
最近比較空閑,公司的后臺就想著把現(xiàn)在的后臺管理系統(tǒng)給改版一下,說是以前的太難看了,用著也不好用,然后給我甩過來一個(gè)ant-design-pro的鏈接,說是他看這個(gè)就挺不錯(cuò)的。
我當(dāng)時(shí)心里就想著,之前的那個(gè)項(xiàng)目混合在你們的java項(xiàng)目里,跟普通的jsp頁面差不多,一下就是一大堆的css和js文件,看著我都害怕(好吧,我承認(rèn)其實(shí)我都不敢看),這能加載的快了就奇了怪了。ant-design最初是為react設(shè)計(jì)的,ant-design-pro自然也是用react了,不得不說人家這個(gè)界面看著確實(shí)舒服。
對著ant-design-pro的官方文檔看了一通,貌似看了跟沒看也差不多???算了,還是直接看代碼吧,整理了一下思路,大致上是看懂了,除了react + react-router外,狀態(tài)管理用的是 dva, redux的異步問題算是解決了,要不就開始直接寫頁面吧?
等等,我好像漏掉了點(diǎn)什么?噢,對,先看看打包出來的文件大小,一打包我的心就涼了,最大的js居然有900多k,ant-design的源文件是真的大。react我還只是能寫出代碼,打包優(yōu)化這個(gè)可就有點(diǎn)為難我了。這時(shí)的我再想到公司那1m的帶寬,還有這幾個(gè)后臺的技術(shù)能力,要不然這個(gè)技術(shù)棧我還是放棄吧?不能指望連 請求頭, CORS稍微高級一點(diǎn)的攜帶cookie, nginx靜態(tài)服務(wù)器 都搞不懂的人去給我弄個(gè)靜態(tài)服務(wù)器,再順便開啟一下gzip吧?算了算了,找找有沒有vue + element-ui的后臺模板,不用太費(fèi)勁就找到了 vue-element-admin 。
vue-element-admin用著還行,就是界面不太符合我的理想情況,就對著ant-design-pro改造了一點(diǎn),列表頁大概就是下面這樣了。列表的數(shù)據(jù)是要分頁的,普通的列表頁只有一個(gè)頁面棧,也就是用戶點(diǎn)擊地址欄的回退地址欄時(shí),會(huì)返回上一個(gè)頁面棧,而不是上一頁的數(shù)據(jù),不太符合用戶習(xí)慣吧?畢竟傳統(tǒng)的網(wǎng)站都是可以回退到上一頁的,嗯,話不多說,進(jìn)入正題吧。
第一步:改變地址欄
假設(shè)列表頁的路徑是 /user/list,分頁相關(guān)的參數(shù)為 { page: 1, pagesize: 10 }
,從其他頁面跳轉(zhuǎn)過來的時(shí)候,我們的路徑通常是不包含任何參數(shù)的,之后的列表數(shù)據(jù)都是根據(jù)該頁面的page和pagesize進(jìn)行變化的,當(dāng)未使用keep-alive緩存組件時(shí),每次進(jìn)入列表頁都相當(dāng)于第一次進(jìn)入,也就是說每次都只能獲取第一頁的數(shù)據(jù)。
既然列表數(shù)據(jù)是用page和pagesize進(jìn)行變化的,那直接從地址欄獲取page和pagesize進(jìn)行賦值不就好了?那么是改變地址欄的代碼是直接寫在當(dāng)前頁面還是 獨(dú)立為分頁組件 呢?從復(fù)用性方面來說,還是獨(dú)立出來的好,畢竟其他頁面可能也會(huì)使用到,總不能每次都復(fù)制粘貼吧,那組件化的意義何在?當(dāng)然了,也不是說分頁就必須用這個(gè)自定義的分頁組件,只推薦在 主頁面(非遮罩層 ,有的頁面會(huì)在點(diǎn)擊某一行數(shù)據(jù)時(shí)出現(xiàn)遮罩層顯示子列表,此時(shí)使用element-ui的分頁組件即可)需要分頁時(shí)使用。
當(dāng)改變地址欄的時(shí)候,我們是不希望不帶分頁參數(shù)的頁面棧存在的,此時(shí)用replace直接替換即可。
MyPagination.vue的初始結(jié)構(gòu)為:
<template> <div class = " flex all-center"> <template v-if="total > 0"> <el-pagination :page-size="pagesize" :total="total" :current-page="page" background layout="prev, pager, next, jumper, total" class="my-pagination" @current-change="changePage" /> </template> </div> </template> <script> export default { name: 'MyPagination', props: { total: { type: Number, default: 0, }, page: { type: Number, default: 1, }, pagesize: { type: Number, default: 10, }, totalPages: { type: Number, default: 1, }, }, created() { this.getCurrentPage(); }, methods: { changePage(val) { this.handlePage('push', val, this.pagesize); this.$emit('change', val, this.pagesize); }, getCurrentPage() { var { page, pagesize } = this.$route.query; if (!page || !pagesize) { this.handlePage('replace', page || 1, +pagesize || this.pagesize); return true; } return false; }, handlePage(type, page, pagesize) { this.$router[type]({ path: this.$route.path, query: { ...this.$route.query, page, pagesize }, }); } }, } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .my-pagination { padding-top: 24px; } </style>
父組件的關(guān)鍵代碼:
<MyPagination :total = "total" :pagesize = "pagesize" :page="page" :totalPages = "totalPages" @change = "changePage" /> methods: { changePage(page, pagesize) { var _page = this.page, _pagesize = this.pagesize; this.page = page; this.pagesize = pagesize; if (page !== _page && pagesize || _pagesize !== pagesize) this.fetchData(); // 非首次進(jìn)入頁面時(shí)再獲取分頁數(shù)據(jù),因?yàn)樵赾reated鉤子中已經(jīng)獲取過一次了。 }, }
實(shí)現(xiàn)效果: 首次進(jìn)入該頁面時(shí),如果不含有分頁參數(shù),就會(huì)先改變分頁參數(shù),然后再獲取數(shù)據(jù),之后點(diǎn)擊分頁組件的頁碼也會(huì)獲取分頁之后的數(shù)據(jù)。
第二步: 觀察路由變化
上一步的實(shí)現(xiàn)效果乍一看好像沒什么不對勁的地方,但是如果直接改變地址欄的話,顯示的當(dāng)前頁和當(dāng)前數(shù)據(jù)都不會(huì)變化。前端路由在頁面的查詢參數(shù)(指的是 router的查詢參數(shù) ,可不是普通頁面的查詢參數(shù))變化時(shí),默認(rèn)是不會(huì)重新加載的,除非頁面的key發(fā)生變化,這樣是為了盡可能的防止頁面重新渲染,所以就不用key的方式解決了,直接通過vue的watch檢測 $route 的變化,從而改變當(dāng)前頁和當(dāng)前數(shù)據(jù)的顯示問題。
在MyPagination.vue中新增:
watch: { '$route'(to, from) { let { page, pagesize } = to.query; if (!this.getCurrentPage()) { this.$emit('change', +page || 1, +pagesize || 10); } } },
第三步: 控制pagesize的大小
在上一步的效果中,當(dāng)改變地址欄的page和pagesize時(shí),列表頁的數(shù)據(jù)也會(huì)隨之變化。既然是根據(jù)地址欄的參數(shù)變化,那么新的問題就產(chǎn)生了,
如果用戶輸入的page大于頁面總數(shù)呢?
這個(gè)時(shí)候主要就看后臺怎么設(shè)計(jì)了,
返回第一頁的數(shù)據(jù)。
getCurrentPage() { var { page, pagesize } = this.$route.query; /* (totalPages > 0 && (page > totalPages));滿足總頁數(shù)大于0且當(dāng)前頁大于總頁數(shù)時(shí),跳轉(zhuǎn)到第一頁 */ if (!page || !pagesize || (totalPages > 0 && (page > totalPages))) { this.handlePage('replace', page || 1, this.pagesize); return true; } return false; },
返回最后一頁的數(shù)據(jù)(我覺得這種操作應(yīng)該是比較合理的)。
getCurrentPage() { var { page, pagesize } = this.$route.query, MAX_PAGESIZE = this.max, totalPages = this.totalPages; if (!page || !pagesize) { this.handlePage('replace', page || 1, +pagesize || this.pagesize); return true; } else if (totalPages > 0 && (page > totalPages)) { this.handlePage('replace', totalPages, +pagesize); return true; } return false; },
替換當(dāng)前頁面棧,return true的作用是阻止watch中的后續(xù)操作,取消本次請求。替換頁面以后,請求遠(yuǎn)程數(shù)據(jù),更新當(dāng)前頁和數(shù)據(jù)的顯示。
返回空數(shù)組(可能大多數(shù)后臺都是這么設(shè)計(jì)的,他們應(yīng)該沒想過page會(huì)大于總頁數(shù)吧)。 代碼與2中的一樣。
上文都是建立在totalPages已確定的情況,如果是首次進(jìn)入頁面的話情況就會(huì)不一樣了。
如果是首次進(jìn)入頁面的話,totalPages第一次是0,也就是地址欄的參數(shù)將不會(huì)發(fā)生變化,這時(shí)候就會(huì)出現(xiàn)地址欄和分頁組件的顯示不一致的情況。這時(shí)候可以在分頁組件中watch totalPages的變化。
totalPages(newVal, oldVal) { if (+oldVal === 0 && newVal > 0) { this.handlePage('replace', this.page, +this.pagesize); } }
如果pagesize過大呢?
pagesize是必須要進(jìn)行限制的,如果太大的話,后臺查詢數(shù)據(jù)就會(huì)非常慢,也可能會(huì)造成壓力。 解決辦法其實(shí)也簡單,就是在props增加一個(gè)max屬性,然后在getCurrentPage方法中進(jìn)行限制,代碼如下:
props: { max: { type: Number, default: 20, }, }, methods: { getCurrentPage() { var { page, pagesize } = this.$route.query, MAX_PAGESIZE = this.max, totalPages = this.totalPages; if (!page || !pagesize) { this.handlePage('replace', page || 1, +pagesize || this.pagesize); return true; } else if (pagesize > MAX_PAGESIZE) { this.handlePage('replace', page, MAX_PAGESIZE); return true; } else if (totalPages > 0 && (page > totalPages)) { this.handlePage('replace', totalPages, +pagesize); return true; } return false; }, },
第四步: 優(yōu)化代碼
點(diǎn)擊分頁組件的頁碼時(shí)產(chǎn)生兩次請求
點(diǎn)擊分頁組件時(shí),1. 會(huì)監(jiān)聽current-change事件并改變地址欄,同時(shí)emit change事件至父組件,2. 但是地址欄改變后,在watch $route也會(huì)emit change事件至父組件,那么只需要合并emit change事件,即current-change事件中只改變地址欄。
changePage(val) { this.handlePage('push', val, this.pagesize); },
結(jié)果
至此,一個(gè)自定義的分頁組件就已經(jīng)實(shí)現(xiàn)了,改變地址欄的參數(shù)就可以看到分頁數(shù)據(jù)的變化了,點(diǎn)擊頁碼時(shí)地址欄也會(huì)隨之而改變,請求數(shù)量已經(jīng)盡可能的減少了。
自定義的分頁組件: MyPagination.vue
列表頁: list.vue
完整demo: front_end
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Vue使用Element-UI實(shí)現(xiàn)分頁效果全過程
- 利用Vue模擬實(shí)現(xiàn)element-ui的分頁器效果
- vue+Element-ui前端實(shí)現(xiàn)分頁效果
- vue+Element-ui實(shí)現(xiàn)分頁效果
- 在vue和element-ui的table中實(shí)現(xiàn)分頁復(fù)選功能
- vue+Element-ui實(shí)現(xiàn)分頁效果實(shí)例代碼詳解
- vue 基于element-ui 分頁組件封裝的實(shí)例代碼
- Vue+element-ui 實(shí)現(xiàn)表格的分頁功能示例
- 利用vue和element-ui設(shè)置表格內(nèi)容分頁的實(shí)例
- vue如何使用element-ui 實(shí)現(xiàn)自定義分頁
相關(guān)文章
使用Vant完成DatetimePicker 日期的選擇器操作
這篇文章主要介紹了使用Vant完成DatetimePicker 日期的選擇器操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11vue項(xiàng)目實(shí)現(xiàn)左滑刪除功能(完整代碼)
最近在開發(fā)移動(dòng)端項(xiàng)目,通過向左滑動(dòng)出現(xiàn)刪除按鈕,點(diǎn)擊即可刪除,怎么實(shí)現(xiàn)這個(gè)功能呢,接下來小編給大家?guī)韺?shí)例代碼幫助大家學(xué)習(xí)vue項(xiàng)目實(shí)現(xiàn)左滑刪除功能,感興趣的朋友跟隨小編一起看看吧2021-05-05vue實(shí)現(xiàn)兩個(gè)區(qū)域滾動(dòng)條同步滾動(dòng)
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)兩個(gè)區(qū)域滾動(dòng)條同步滾動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12Vue實(shí)現(xiàn)兩種路由權(quán)限控制方式
路由權(quán)限控制常用于后臺管理系統(tǒng)中,對不同業(yè)務(wù)人員能夠訪問的頁面進(jìn)行一個(gè)權(quán)限的限制。本文主要介紹了兩種Vue 路由權(quán)限控制,具有一定的參考價(jià)值,感興趣的可以了解一下2021-10-10Vue3超詳細(xì)的ref()用法教程(看這一篇就夠了!)
這篇文章主要給大家介紹了關(guān)于Vue3超詳細(xì)的ref()用法的相關(guān)資料,在Vue3中ref函數(shù)不僅可以用于在組件中獲取DOM元素或子組件的引用,還可以直接訪問組件元素本身,需要的朋友可以參考下2023-07-07