vue + element-ui的分页问题实现


Posted in Javascript onDecember 17, 2018

背景介绍

最近比较空闲,公司的后台就想着把现在的后台管理系统给改版一下,说是以前的太难看了,用着也不好用,然后给我甩过来一个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改造了一点,列表页大概就是下面这样了。列表的数据是要分页的,普通的列表页只有一个页面栈,也就是用户点击地址栏的回退地址栏时,会返回上一个页面栈,而不是上一页的数据,不太符合用户习惯吧?毕竟传统的网站都是可以回退到上一页的,嗯,话不多说,进入正题吧。

vue + element-ui的分页问题实现 

第一步:改变地址栏

假设列表页的路径是 /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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
获取焦点时,利用js定时器设定时间执行动作
Apr 02 Javascript
Node.js本地文件操作之文件拷贝与目录遍历的方法
Feb 16 Javascript
论JavaScript模块化编程
Mar 07 Javascript
老生常谈 js中this的指向
Jun 30 Javascript
利用Js+Css实现折纸动态导航效果实例源码
Jan 25 Javascript
jQuery返回定位插件详解
May 15 jQuery
vue-router实现组件间的跳转(参数传递)
Nov 07 Javascript
jQuery实现带右侧索引功能的通讯录示例【附源码下载】
Apr 17 jQuery
vue2.0使用v-for循环制作多级嵌套菜单栏
Jun 25 Javascript
vue中将html字符串转换成html后遇到的问题小结
Dec 10 Javascript
微信小程序实现弹出菜单动画
Jun 21 Javascript
vue跳转同一个组件,参数不同,页面接收值只接收一次的解决方法
Nov 05 Javascript
Vue 中的受控与非受控组件的实现
Dec 17 #Javascript
js实现移动端轮播图
Dec 21 #Javascript
微信小程序登录按钮遮罩浮层效果的实现方法
Dec 16 #Javascript
微信小程序 JS动态修改样式的实现方法
Dec 16 #Javascript
Echart折线图手柄触发事件示例详解
Dec 16 #Javascript
vue使用pdfjs显示PDF可复制的实现方法
Dec 14 #Javascript
antd Upload 文件上传的示例代码
Dec 14 #Javascript
You might like
Thinkphp5 微信公众号token验证不成功的原因及解决方法
2017/11/12 PHP
prototype Element学习笔记(篇二)
2008/10/26 Javascript
javascript的数据类型、字面量、变量介绍
2012/05/23 Javascript
js实现类似新浪微博首页内容渐显效果的方法
2015/04/10 Javascript
使用JQuery实现Ctrl+Enter提交表单的方法
2015/10/22 Javascript
详解AngularJS 模态对话框
2016/04/07 Javascript
两种方法解决javascript url post 特殊字符转义 + &amp; #
2016/04/13 Javascript
jquery+CSS3实现3D拖拽相册效果
2016/07/18 Javascript
jQuery组件easyui基本布局实现代码
2016/08/25 Javascript
使用bootstrap validator的remote验证代码经验分享(推荐)
2016/09/21 Javascript
JS声明式函数与赋值式函数实例分析
2016/12/13 Javascript
Vue2.0使用过程常见的一些问题总结学习
2017/04/10 Javascript
关于vue-cli 3配置打包优化要点(推荐)
2019/04/22 Javascript
p5.js临摹动态图形的方法
2019/10/23 Javascript
原生js实现商品筛选功能
2019/10/28 Javascript
vue添加锚点,实现滚动页面时锚点添加相应的class操作
2020/08/10 Javascript
[14:20]刀塔大凶女神互压各路奇葩屌丝
2014/05/16 DOTA
[02:34]2016完美“圣”典风云人物:BurNIng专访
2016/12/10 DOTA
python 判断自定义对象类型
2009/03/21 Python
python用于url解码和中文解析的小脚本(python url decoder)
2013/08/11 Python
在Python中处理日期和时间的基本知识点整理汇总
2015/05/22 Python
Python实现股市信息下载的方法
2015/06/15 Python
各种Python库安装包下载地址与安装过程详细介绍(Windows版)
2016/11/02 Python
Pyqt5实现英文学习词典
2019/06/24 Python
python3实现微型的web服务器
2019/09/03 Python
Pythonic版二分查找实现过程原理解析
2020/08/11 Python
通过实例解析Python文件操作实现步骤
2020/09/21 Python
美国马匹用品和骑马配件购物网站:Horse.com
2018/01/08 全球购物
美国爆米花工厂:The Popcorn Factory
2019/09/14 全球购物
敏捷开发的主要原则都有哪些
2015/04/26 面试题
ktv中秋节活动方案
2014/01/30 职场文书
优良学风班总结材料
2014/02/08 职场文书
国际商务专业毕业生自我鉴定2014
2014/09/27 职场文书
2014年小学工作总结
2014/11/26 职场文书
Java面试题冲刺第十九天--数据库(4)
2021/08/07 Java/Android
Java9新特性之Module模块化编程示例演绎
2022/03/16 Java/Android