国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

vue + element-ui的分頁問題實現

2019-11-19 12:20:19
字體:
來源:轉載
供稿:網友

背景介紹

最近比較空閑,公司的后臺就想著把現在的后臺管理系統給改版一下,說是以前的太難看了,用著也不好用,然后給我甩過來一個ant-design-pro的鏈接,說是他看這個就挺不錯的。

我當時心里就想著,之前的那個項目混合在你們的java項目里,跟普通的jsp頁面差不多,一下就是一大堆的css和js文件,看著我都害怕(好吧,我承認其實我都不敢看),這能加載的快了就奇了怪了。ant-design最初是為react設計的,ant-design-pro自然也是用react了,不得不說人家這個界面看著確實舒服。

對著ant-design-pro的官方文檔看了一通,貌似看了跟沒看也差不多???算了,還是直接看代碼吧,整理了一下思路,大致上是看懂了,除了react + react-router外,狀態管理用的是 dva, redux的異步問題算是解決了,要不就開始直接寫頁面吧?

等等,我好像漏掉了點什么?噢,對,先看看打包出來的文件大小,一打包我的心就涼了,最大的js居然有900多k,ant-design的源文件是真的大。react我還只是能寫出代碼,打包優化這個可就有點為難我了。這時的我再想到公司那1m的帶寬,還有這幾個后臺的技術能力,要不然這個技術棧我還是放棄吧?不能指望連 請求頭, CORS稍微高級一點的攜帶cookie, nginx靜態服務器 都搞不懂的人去給我弄個靜態服務器,再順便開啟一下gzip吧?算了算了,找找有沒有vue + element-ui的后臺模板,不用太費勁就找到了 vue-element-admin

vue-element-admin用著還行,就是界面不太符合我的理想情況,就對著ant-design-pro改造了一點,列表頁大概就是下面這樣了。列表的數據是要分頁的,普通的列表頁只有一個頁面棧,也就是用戶點擊地址欄的回退地址欄時,會返回上一個頁面棧,而不是上一頁的數據,不太符合用戶習慣吧?畢竟傳統的網站都是可以回退到上一頁的,嗯,話不多說,進入正題吧。

 

第一步:改變地址欄

假設列表頁的路徑是 /user/list,分頁相關的參數為 { page: 1, pagesize: 10 } ,從其他頁面跳轉過來的時候,我們的路徑通常是不包含任何參數的,之后的列表數據都是根據該頁面的page和pagesize進行變化的,當未使用keep-alive緩存組件時,每次進入列表頁都相當于第一次進入,也就是說每次都只能獲取第一頁的數據。

既然列表數據是用page和pagesize進行變化的,那直接從地址欄獲取page和pagesize進行賦值不就好了?那么是改變地址欄的代碼是直接寫在當前頁面還是 獨立為分頁組件 呢?從復用性方面來說,還是獨立出來的好,畢竟其他頁面可能也會使用到,總不能每次都復制粘貼吧,那組件化的意義何在?當然了,也不是說分頁就必須用這個自定義的分頁組件,只推薦在 主頁面(非遮罩層 ,有的頁面會在點擊某一行數據時出現遮罩層顯示子列表,此時使用element-ui的分頁組件即可)需要分頁時使用。

當改變地址欄的時候,我們是不希望不帶分頁參數的頁面棧存在的,此時用replace直接替換即可。

MyPagination.vue的初始結構為:

<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>

父組件的關鍵代碼:

<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(); // 非首次進入頁面時再獲取分頁數據,因為在created鉤子中已經獲取過一次了。 },}

實現效果: 首次進入該頁面時,如果不含有分頁參數,就會先改變分頁參數,然后再獲取數據,之后點擊分頁組件的頁碼也會獲取分頁之后的數據。

第二步: 觀察路由變化

上一步的實現效果乍一看好像沒什么不對勁的地方,但是如果直接改變地址欄的話,顯示的當前頁和當前數據都不會變化。前端路由在頁面的查詢參數(指的是 router的查詢參數 ,可不是普通頁面的查詢參數)變化時,默認是不會重新加載的,除非頁面的key發生變化,這樣是為了盡可能的防止頁面重新渲染,所以就不用key的方式解決了,直接通過vue的watch檢測 $route 的變化,從而改變當前頁和當前數據的顯示問題。

在MyPagination.vue中新增:

watch: { '$route'(to, from) {  let { page, pagesize } = to.query;  if (!this.getCurrentPage()) {  this.$emit('change', +page || 1, +pagesize || 10);  } }},

第三步: 控制pagesize的大小

在上一步的效果中,當改變地址欄的page和pagesize時,列表頁的數據也會隨之變化。既然是根據地址欄的參數變化,那么新的問題就產生了,

如果用戶輸入的page大于頁面總數呢?

這個時候主要就看后臺怎么設計了,

返回第一頁的數據。

getCurrentPage() { var { page, pagesize } = this.$route.query; /*  (totalPages > 0 && (page > totalPages));滿足總頁數大于0且當前頁大于總頁數時,跳轉到第一頁 */ if (!page || !pagesize || (totalPages > 0 && (page > totalPages))) { this.handlePage('replace', page || 1, this.pagesize); return true; } return false;},

返回最后一頁的數據(我覺得這種操作應該是比較合理的)。

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;},

替換當前頁面棧,return true的作用是阻止watch中的后續操作,取消本次請求。替換頁面以后,請求遠程數據,更新當前頁和數據的顯示。

返回空數組(可能大多數后臺都是這么設計的,他們應該沒想過page會大于總頁數吧)。 代碼與2中的一樣。

上文都是建立在totalPages已確定的情況,如果是首次進入頁面的話情況就會不一樣了。

如果是首次進入頁面的話,totalPages第一次是0,也就是地址欄的參數將不會發生變化,這時候就會出現地址欄和分頁組件的顯示不一致的情況。這時候可以在分頁組件中watch totalPages的變化。

totalPages(newVal, oldVal) { if (+oldVal === 0 && newVal > 0) { this.handlePage('replace', this.page, +this.pagesize); }}

如果pagesize過大呢?

pagesize是必須要進行限制的,如果太大的話,后臺查詢數據就會非常慢,也可能會造成壓力。 解決辦法其實也簡單,就是在props增加一個max屬性,然后在getCurrentPage方法中進行限制,代碼如下:

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; },},

第四步: 優化代碼

點擊分頁組件的頁碼時產生兩次請求

點擊分頁組件時,1. 會監聽current-change事件并改變地址欄,同時emit change事件至父組件,2. 但是地址欄改變后,在watch $route也會emit change事件至父組件,那么只需要合并emit change事件,即current-change事件中只改變地址欄。

changePage(val) { this.handlePage('push', val, this.pagesize);},

結果

至此,一個自定義的分頁組件就已經實現了,改變地址欄的參數就可以看到分頁數據的變化了,點擊頁碼時地址欄也會隨之而改變,請求數量已經盡可能的減少了。

自定義的分頁組件: MyPagination.vue

列表頁: list.vue

完整demo: front_end

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 敦煌市| 克东县| 嵊泗县| 商南县| 常州市| 万州区| 南投市| 潞西市| 四子王旗| 济源市| 阿合奇县| 茌平县| 望奎县| 庆元县| 尤溪县| 延寿县| 秭归县| 榆中县| 定结县| 石城县| 綦江县| 商城县| 宁陵县| 米易县| 顺昌县| 梁河县| 潜山县| 茂名市| 蕉岭县| 苏尼特左旗| 青冈县| 伊通| 讷河市| 彰化县| 水富县| 南澳县| 阿荣旗| 张掖市| 全州县| 宝兴县| 松潘县|