简单封装分页功能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方式开发的,可能没了解过的人,不知道它是做什么用,关于它的介绍都在下面这篇文章里面:

详解Javascript的继承实现

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)对于分页算法,我认为在产品设计中没有必要做出太多的不同的设计出来,所以固化一种没有问题。因为不管从哪一方面,为不同的页面提供不同的分页算法都是一件很划不来的事情,如果当产品出现这种问题的时候,我会尽力去把他说服。

当然,每个人想法不同,坚持自己的思想最好。

最后希望本文多少对大家有点用处,谢谢阅读:)

时间: 2024-10-10 23:05:36

简单封装分页功能pageView.js的相关文章

AngularJS实现简单的分页功能

本篇文章由:http://xinpure.com/angularjs-simple-paging-functionality/ 初学 AngularJS, 尝试着写一些小功能 代码逻辑写得略粗糙,仅仅只是实现了简单的分页功能,使用 AngularJS 尝尝鲜. AngularJS Code (Users.js) var Users = angular.module('Users', []); Users.controller('UserList', function($scope, $http)

封装分页功能

#import <UIKit/UIKit.h> @interface LZJPageView : UIView /** 图片名数据 */ @property (nonatomic, strong) NSArray *imageNames; + (instancetype)pageView; @end #import "LZJPageView.h" @interface LZJPageView () <UIScrollViewDelegate> @property

MyBatis精通之路之分页功能的实现

MyBatis精通之路之分页功能的实现(数组分页.sql分页.拦截器,RowBounds分页) 原创 2017年04月27日 21:34:48 标签: mybatis / java / j2ee / mysql / 分页 4162 前言:学习hibernate & mybatis等持久层框架的时候,不外乎对数据库的增删改查操作.而使用最多的当是数据库的查找操作, 而当数据库数据过多时,符合查找条件的数据可能也会是很庞大的数据.往往在这个时候,我们都不会希望一次性的将所有的数据一起性读取出来,并且

jsp、js分页功能的简单总结

一.概述 首先,我们要明确为何需要分页技术,主要原因有以下: 1.分页可以提高客户体验度,适当地选择合适的数据条数,让页面显得更有条理,使得用户体验感良好,避免过多数据的冗余. 2.提高性能的需要.分页技术,有选择的加载某部分数据,在数据量较大的时候,分部分加载数据.显示数据,可以有效提高程序的性能,当然,单纯的js的分页技术并没有这种效果. 所以,分页技术是web技术中比较常用的技术,而下面讨论的主要是两种分页技术:一种是jsp的分页技术,其读取数据分批次读取,操作页数跳转的时候才加载相应页面

js+html+css实现简单页面交互功能(2015知乎前端笔试题)http://v.youku.com/v_show/id_XMTI0ODQ5NTAyOA==.html?from=y1.7-1.2

js+html+css实现简单页面交互功能(2015知乎前端笔试题) http://v.youku.com/v_show/id_XMTI0ODQ5NTAyOA==.html?from=y1.7-1.2 密码:hellozhihu

使用JS完成一个简单的计算器功能

使用JS完成一个简单的计算器功能.实现2个输入框中输入整数后,点击第三个输入框能给出2个整数的加减乘除. 提示:获取元素的值设置和获取方法为:例:赋值:document.getElementById("id").value = 1: 取值:var = document.getElementById("id").value: 任务 第一步: 创建构建运算函数count(). 第二步: 获取两个输入框中的值和获取选择框的值. 提示:document.getElement

一个js实现的分页功能

分页,一直是个令我头疼的问题,用java写网站的时候 ,需要用到分页功能,那时候是定义一个分页用的类,感觉比较麻烦,不过在数据量大的时候,应该会比较合适 去年做项目的过程中,用的是下拉刷新的组件,是别人写的,实现起来不方便, 效果也不太好 偶然在网上看到过js的分页功能,想想既然java能实现,js肯定是也能实现的. 参考网上的内容,稍微修改了下,暂且称之为0.1版 具体方法:先将所有的数据取出来,并用html展示出来,但用js去控制html标签的显示与隐藏,算是从另一个角度实现了分页功能 这一

简单的beego分页功能代码

一个简单的beego分页小插件(源代码在最下面): 支持条件查询 支持参数保留 支持自定义css样式 支持表/视图 支持参数自定义 默认为pno 支持定义生成链接的个数 使用方式: 1)action中,引入包,然后如下使用: /** * 日志列表 */ func (this *LogController) List() { pno, _ := this.GetInt("pno") //获取当前请求页 var tlog []m.Tb_log var conditions string =

Node.js 博客实例(七)分页功能

原教程 https://github.com/nswbmw/N-blog/wiki/_pages的第七章,由于版本等的原因,在原教程基础上稍加改动即可实现. 给博客的主页和用户页面增加分页功能.设定:主页和用户页面每页最多显示十篇文章. 这里要用到 mongodb 的 skip 和 limit 操作. 打开 post.js ,把 Post.getAll 函数修改如下: //读取文章及其相关信息 Post.getTen = function(name,page,callback) { //打开数据