简单封装分页功能pageView.js
分页是一个很简单,通用的功能。作为一个有经验的前端开发人员,有义务把代码中类似这样公共的基础性的东西抽象出来,一来是改善代码的整体质量,更重要的是为了将来做类似的功能或者类似的项目,能减少不必要的重复工作量。在实际项目中,尤其是网站类型的项目中,分页部分的设计总是个性化比较强,基本上都不会长的一样,所以可能之前抽象出来的东西,如果写的不够灵活的话,对这些个性化强的项目来说,可能直接应用的时候也得做些调整才行。本文尝试提供一个尽量满足这两方面要求的分页组件。
先介绍下写这个东西的背景:一直以来,我都想写一个相对比较灵活简单的列表组件,去年写过一个版本,后来改了几次,现在已经用到好几个项目里面去了,重构起来也有不少的工作量,因为应用到的页面已经把比较多了,所以就没有轻易地去做这个事情。最近的工作,涉及到一个相对简单的列表页面,然后给的时间也比较多,于是我准备趁这个时候把我一直想写的列表组件给写出来。现有的那个列表管理组件,没有做好职责分离,列表的管理跟分页的管理是揉在一起的,代码也比较乱,所以这次我打算先从分页组件下手。因为分页组件与列表之间并没有太多耦合的逻辑,所以当把它们分离出来的时候,代码会更加清晰,独立,将来要维护也方便些。前端虽然做不到像后台那样,考虑那么多的设计模式,但要是能把代码写的更让人容易理解的话,对团队对公司来说,真的是一件很好的事情。
虽然网上有不少的分页插件,但是都不值得去用,一来是有轻微的学习成本,二来是不符合自己的封装的思想,看着别扭;而且像这样简单的封装,最适合自己动手去写,加强面向对象编程的锻炼了。
下面就开始这个分页组件的内容。
基本思想
先来说下我的基本想法。分页这个部分,从内容上可能包括有:上一页,首页,下一页,尾页以及具体页;页码输入跳转;分页大小;记录总数;记录范围等;从结构上,必须知道分页大小,当前页的索引以及记录总数才能构造所有的内容;从操作上:改变分页大小,或者是点击上一页,首页,下一页,尾页以及具体页,或者是直接输入页码,都会引发外部分页内容的拉取。对外部来说,不管分页部分做什么操作,只要在这些操作之后,通知外部去拉取即可,分页只需要提供一个简单的api给外部,告诉它们当前的分页大小和页码;但是在外部拉取到新的内容之后,还得做一件事情,就是要根据最新的记录总数,去更新分页部分的UI,前面说分页的内容需要记录总数,页码和分页大小才能构造出来。由于页码跟分页大小都属于分页内部管理的,所以外部更新分页UI的时候,只需要告诉分页最新的记录数就够了。以上就是分页组件跟外部功能互相交互时候的唯一场景,基于这些,就可以把所以把分页相关的东西都封装起来,给外部提供几个简单的api来实现它们之间的调用关系,最终完成我们需要的分离的目的。
效果演示
方便大家看到这个东西的实际用法跟效果,我模拟真实的场景,写了一个简单的demo,一起来看看。
demo效果:
demo地址:
http://liuyunzhuge.github.io/blog/form/dist/html/pageView.html
pageView相关css:
https://github.com/liuyunzhuge/blog/blob/master/form/src/css/page_view.css
pageView.js源码:
https://github.com/liuyunzhuge/blog/blob/master/form/src/js/mod/pageView.js
demo相关的源码:
https://github.com/liuyunzhuge/blog/blob/master/form/src/js/app/pageView.js
源码部分也可以直接打开demo地址,通过chrome的开发者工具来查看,因为这些代码放在git上面,是跟我以前的代码放在一块的,怕不知道的人还以为这么个小东西,还需要写那么多个文件。再补充下其它方面的说明:这些代码都是用seajs管理的,然后整个pageView.js是用我自己之前写的一个用来做js的面向对象编程的模块class.js方式开发的,可能没了解过的人,不知道它是做什么用,关于它的介绍都在下面这篇文章里面:
DEMO解析
直接看我在demo里,完成那个页面的核心代码:
从上面的代码也能看出,这个分页组件最核心的api也就是下面几个:
getParams():它是一个实例方法,返回组件的分页大小跟页码,至于这两个值的参数名字,可以通过option来修改;
refresh(total):这也是一个实例方法,外部传给它一个最新的记录总数,分页组件再根据它重新渲染UI;
onChange:这是一个函数类型的回调,它可以作为一个option在创建实例的时候传入,所有分页操作都会反馈到这个回调里面来,通常只要把外部拉取内容的动作绑定它上面即可。
考虑到要控制分页的重复操作问题,还另外加了一个disable和enable的api,这个比较好理解了。当分页被disable的时候,会显示禁用的样式,cursor为not-allowed,所有分页操作都将无效。
实际上,我在最近的一个项目中, 写类似demo的一个简单分页功能,就是这么写的,业务代码很少,逻辑也比较清晰,虽然说列表管理,比如渲染那一块,还可以再封装一下,但是在这种简单场景中,不再去封装,也是可以的,因为它本身已经很简单,再想办法封装,也增加不了多少的灵活性。
现在还有不少的公司在采用没有封装的代码,分页的功能在不同的页面都写一遍,每个位置都定义五六个function,比如goFirst goPrev goLast goNext goPage这种,从结果上来说没啥不好,就是在做重复的事情的时候效率不高,不好维护。要是都能封装起来,相信能给团队带来不少好处。
概要说明
先从option说起,以下是pageView.js定义的所有option及默认值:
var DEFAULTS = {
defaultIndex: 1,//默认页
defaultSize: 10,//默认分页大小
pageIndexName: 'page',//分页参数名称
pageSizeName: 'page_size',//分页大小参数名称
onChange: $.noop,//分页改变或分页大小改变时的回调
onInit: $.noop,//初始化完毕的回调
allowActiveClick: true,//控制当前页是否允许重复点击刷新
middlePageItems: 4,//中间连续部分显示的分页项
frontPageItems: 3,//分页起始部分最多显示3个分页项,否则就会出现省略分页项
backPageItems: 2,//分页结束部分最多显示2个分页项,否则就会出现省略分页项
ellipseText: '...',//中间省略部分的文本
prevText: '上一页',
nextText: '下一页',
prevDisplay: true,//是否显示上一页按钮
nextDisplay: true,//是否显示下一页按钮
firstText: '首页',
lastText: '尾页',
firstDisplay: false,//是否显示首页按钮
lastDisplay: false,//是否显示尾页按钮
};
我把其中需要再详细解释下的说明清楚。
1)pageIndexName和pageSizeName
这两个用来定义分页参数的名字,还记得那个getParams方法吗,它是这样的:
getParams返回一个对象,这个对象包含两个键值对,键分别用pageIndexName和pageSizeName这两个option,值就用分页内部管理的分页大小和页码。当外部调用这个方法时,就能直接把它的返回值作为查询参数传递到后台接口了。
2) middlePageItems,frontPageItems,endPageItems
也许看了demo里面的分页部分的效果就能明白它们三个的作用:
middlePageItems代表中间连续部分的分页项的数量;
frontPageItems代表起始部分连续的分页项的数量;
endPageItems代表结尾部分连续的分页项的数量。
这三个option之所以要定义,是由当前这个分页组件要做的效果,以及它使用的分页算法决定的。
然后pageView定义的实例方法就不过多说明了,因为都比较简单,而且最核心的都已经在demo里面体现出来,感兴趣的话,照着用即可。如果对代码感兴趣,碰到有疑问的,欢迎私信一起交流。
最后说下分页算法。影响分页组件能不能通用的另外一个要素就是分页算法。有的可能不需要分页算法,直接从1到总页数显示出来就完了,但是这样肯定有问题,尤其当总页数很多的时候;有的分页跟我这个就不太一样,它可能只显示当前页在内的连续一部分页码,然后当切换不同的页的时候,这个连续部分也不相同;我这里用的是较为常见的一个算法,首尾以及中间都有连续部分。详细的渲染逻辑都在render方法里面,但是最核心的东西其实还是getInterval这个函数:
function getInterval(data, opts) {
var ne_half = Math.ceil(opts.middlePageItems / 2);
var np = data.pages;
var upper_limit = np - opts.middlePageItems;
var start = data.pageIndex > ne_half ? Math.max(Math.min(data.pageIndex - ne_half, upper_limit), 0) : 0;
var end = data.pageIndex > ne_half ? Math.min(data.pageIndex + ne_half, np) : Math.min(opts.middlePageItems, np);
return [start, end];
}
它的作用在于返回中间连续部分的起止索引。根据这个起止索引渲染中间部分的页码,然后把start和frontPagetItems比较,渲染起始部分的页码;把end与与backPageItems比较,绘制结尾部分的页码。
其它问题
以上就算是这个分页组件的全部核心内容了。但是最终来看,它还是有些问题的。一开始我就说过,这种东西要是能做到足够灵活,能够满足不同项目里面相同功能的话,这样就才算强大。基于这点来看目前的pageView,它的问题在于:
1)固化了分页算法,要是换一个项目,产品不想搞这个分成首尾中间连续三部分的效果,那么就必须改动源码才能适应需求了。要解决这个问题,可以考虑把pageView再抽象出一个父类,不同的子类去覆盖render方法,也就是在项目中提供多个pageView的实现,要用哪个,根据需求来定。
2)没有包括分页大小,页码跳转,记录总数和记录范围这些内容,有可能其他项目需要这些东西,作为分页的辅助功能。要解决这个问题,可以考虑在当前的版本上扩充,补充事件的监听,添加一些合适的option,控制这些内容是否显示即可。
我之所以没有去解决上面的这些问题,有两个原因:
1)就目前的所有场景来说,没有碰到要额外内容的场景,如分页大小等,所以先不处理,避免增加这个组件的复杂性;
2)对于分页算法,我认为在产品设计中没有必要做出太多的不同的设计出来,所以固化一种没有问题。因为不管从哪一方面,为不同的页面提供不同的分页算法都是一件很划不来的事情,如果当产品出现这种问题的时候,我会尽力去把他说服。
当然,每个人想法不同,坚持自己的思想最好。
最后希望本文多少对大家有点用处,谢谢阅读:)
简单封装分页功能pageView.js的更多相关文章
- AngularJS实现简单的分页功能
本篇文章由:http://xinpure.com/angularjs-simple-paging-functionality/ 初学 AngularJS, 尝试着写一些小功能 代码逻辑写得略粗糙,仅仅 ...
- Python odoo中嵌入html简单的分页功能
在odoo中,通过iframe嵌入 html,页面数据则通过controllers获取,使用jinja2模板传值渲染 html页面分页内容,这里写了判断逻辑 <!-- 分页 -->< ...
- 作为一个Java程序员连简单的分页功能都会写,你好意思嘛!
今天想说的就是能够在我们操作数据库的时候更简单的更高效的实现,现成的CRUD接口直接调用,方便快捷,不用再写复杂的sql,带吗简单易懂,话不多说上方法 1.Utils.java工具类中的方法 1 /* ...
- Jquery、Ajax实现新闻列表页分页功能
前端页面官网的开发,离不开新闻列表,新闻列表一般都会有分页的功能,下面是我自己总结加查找网上资料写的一个分页的功能,记录一下. 首先,官网的开发建立在前后端分离的基础上: 再有,后端小伙伴们提供列表页 ...
- WPF最简单的分页控件
背景:最近在写项目的时候需要写一个简单的分页功能,因项目需要,没有改为MVVM模式,只需要在后台实现 1.呈现效果如下: 接下来就来上代码,看看怎么实现的 1.界面代码 <StackPanel ...
- jsp、js分页功能的简单总结
一.概述 首先,我们要明确为何需要分页技术,主要原因有以下: 1.分页可以提高客户体验度,适当地选择合适的数据条数,让页面显得更有条理,使得用户体验感良好,避免过多数据的冗余. 2.提高性能的需要.分 ...
- 自己封装的JS分页功能[用于搭配后台使用]
* 2016.7.03 修复bug,优化代码逻辑 * 2016.5.25 修复如果找不到目标对象的错误抛出. * 2016.5.11 修复当实际页数(pageNumber)小于生成的页码间隔数时的bu ...
- C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi
C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...
- jquery ajax json简单的分页,模拟数据,没有封装,只显示原理
简单的分页,模拟数据,没有封装,显示原理,大家有兴趣可以自己封装,这里只是个原理过程,真正的分页也差不多是这个原理,只是请求数据不太一样,html部分: <!TOCTYPE HTML> & ...
随机推荐
- 关于VS2015 ASP.NET MVC添加控制器的时候报错
调试环境:VS2015 数据库Mysql WIN10 在调试过程中出现类似下两图的同学们,注意啦. 其实也是在学习的过程中遇到这个问题的,找了很多资料都没有正面的解决添加控制器的时候报错的问题,还是 ...
- AI人工智能系列随笔
初探 AI人工智能系列随笔:syntaxnet 初探(1)
- javascript设计模式:策略模式
前言 策略模式有效利用组合.委托.多态等技术和思想,可以有效避免多重条件选择语句. 策略模式对开放-封闭原则提供了很好的支持,将算法封装在strategy中,使得他们易于切换.理解.扩展. 策略模式中 ...
- var和dynamic的区别
1.var 1.均是声明动态类型的变量. 2.在编译阶段已经确定类型,在初始化的时候必须提供初始化的值. 3.无法作为方法参数类型,也无法作为返回值类型. 2.dynamic 1.均是声明动态类型的变 ...
- 基于NPOI的Excel数据导入
从Excel导入数据最令人头疼的是数据格式的兼容性,特别是日期类型的兼容性.为了能够无脑导入日期,折腾了一天的NPOI.在经过测试确实可以导入任意格式的合法日期后,写下这篇小文,与大家共享.完整代码请 ...
- springmvc SSM 多数据源 shiro redis 后台框架 整合
A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址 ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...
- Ajax.BeginForm方法 参数
感谢博主 http://www.cnblogs.com/zzgblog/p/5454019.html toyoung 在Asp.Net的MVC中的语法,在Razor页面中使用,替代JQuery的Aja ...
- Spring MVC初始化参数绑定
初始化参数绑定与类型转换很类似,初始化绑定时,主要是参数类型 ---单日期 在处理器类中配置绑定方法 使用@InitBinder注解 在这里首先注册一个用户编辑器 参数一为目标类型 proper ...
- Salesforce开发者学习笔记之一:基本知识
本文介绍了Salesforce开发平台的基本知识, 包括如下内容: Salesforce平台介绍 Salesforce基本术语 定制和扩展Salesforce平台 创建一个简单的应用程序 Salesf ...
- 【repost】JS中的异常处理方法分享
我们在编写js过程中,难免会遇到一些代码错误问题,需要找出来,有些时候怕因为js问题导致用户体验差,这里给出一些解决方法 js容错语句,就是js出错也不提示错误(防止浏览器右下角有个黄色的三角符号,要 ...