收获:
1.总架构:
首先创建BootstrapPaginator构造函数,prototype赋值方法,实现页面的渲染,通过自调用匿名函数封装BootstrapPaginator类的方法,对外不提供修改及调用接口,onPageClicked方法用来改变页码的显示状况;
再在$.fn.BootstrapPaginator内部new出一个BootstrapPaginator实例,构成jquery插件,默认配置项作为$.fn.BootstrapPaginator的属性存在,包括前后首尾页的显示文本、提示层文本、尺寸对齐等样式状况、以及onPageClicked、onPageChanged方法,onPageClicked修改页面显示状况,onPageChanged用于前后台的数据交互,因为BootstrapPaginator类和$.fn.BootstrapPaginator插件没有继承、相等关系,两个同名的onPageClicked方法也不会起冲突,通过不同的事件绑定分别调用两个同名方法。
2.BootstrapPaginator类的构造:
init方法初始化,构造函数当即执行该方法,该方法内部调用setOptions调用配置项;
setOptions设置配置项,调用listen方法绑定事件、render方法渲染页面;
listen方法绑定BootstrapPaginator类的onPageClicked方法以及$.fn.BootstrapPaginator插件中的onPageClicked、onPageChanged方法;
render方法创建包裹元素ul,设置尺寸、对齐方式,调用builPageItem方法判断前一页、后一页、首页、尾页、页码的显示情况,创建对应li及a子元素;
buildPageItem方法创建li、a子元素,添加li、a的文本内容、提示层,a元素中绑定BootstrapPaginator类的onPageItemClicked方法,以此改变页面样式,或者通过跳链接的方式实现页面内容的切换,替代前后台数据交互;
onPageItemClicked方法通过触发page-clicked事件调用BootstrapPaginator类的onPageClicked方法以及$.fn.BootstrapPaginator插件中的onPageClicked方法
onPageClicked方法通过点击分页区域改变页面样式,调用showFirst、showLast、showNext、showPrev、show方法实现;
showFirst、showLast、showNext、showPrev方法通过调用getPages方法以数组形式记录页码显示状况,调用show方法设置当前页、渲染页面、绑定page-changed事件;
getPages方法以数组形式记录页码的显示状况,并且以数组的属性记录当前页、前一页、后一页、首页、尾页、显示页码的个数,方便调用,以作判断;
show方法设置当前页、调用render方法渲染页面、绑定page-changed事件,触发onPageChanged方法;
getValueFromOption方法,参数的第一项为函数的时候,将参数的其余项传入该函数构造输出,否则直接将参数输出。
getValueFromOption方法、类的设计较有深意。
3.jquery的新认识:
$.on("eventtype",[selector],[data],fn)...selector事件捕获阶段查询的子节点,data是传入event.data中的数据;
$.proxy(fn,content)...fn的作用域改成content,并返回fn;
$("element").on("eventtype",fn)...绑定事件;
$("element").trigger("eventtype",[arguments])触发事件,并传入arguments参数;
$("element").data()...获取或设置元素的data数据,该数据添加到dom元素中不会在元素的属性中显示;
typeof data...自动截取data的第一项作判断;
data.apply(this,arguments)...data的第一项为函数的时候,执行apply方法,改变该函数的作用域,设置传入的参数。
4.插件的使用:
版本为2的时候页面元素只能是div,版本为3的时候只能是ul
onPageClicked用于改变页面样式,onPageChanged实现数据交互
插件提供了跳连接的方式实现页面交互,可通过修改配置项的pageUrl函数
itemTexts函数修改显示文本,tooltipTitles修改提示文本
实例:
html:
<ul id="pagination"></ul>
js:
var options={ currentPage: 1, totalPages: 25, numberofPages: 5, itemTexts: function(type, page, current) { switch (type) { case "first": return "第一页"; case "prev": return "上一页"; case "next": return "下一页"; case "last": return "最后一页"; case "page": return page; } }, onPageChanged: function (event,lastpage, currentpage) { $.post("",{page:currentpage},function(data) { }); }, pageUrl: function (type,page, currentpage) { return "/***.htm?currentpage="+page }, //跳链接的方式 }; $("#pagination").bootstrapPaginator(options);
5.插件存在的缺点,或者预留的可扩展部分
通过清除包裹元素的样式,再调用containerClass函数的方式添加样式未免多此一举。
余不赘述
6.源码:
(function ($) { "use strict"; //先创建分页的构造函数,作为公有方法,再将该构造函数通过new方法赋在$.fn.bootstrapPaginator内部形成jquery插件 //默认项在$.fn.bootstrapPaginator.defaults中定义,包含显示前一页的显示文本、是否显示以及提示文字,可修改部分 var BootstrapPaginator = function (element, options) { this.init(element, options); }, old = null; BootstrapPaginator.prototype = { init: function (element, options) { this.$element = $(element); var version = (options && options.bootstrapMajorVersion) ? options.bootstrapMajorVersion : $.fn.bootstrapPaginator.defaults.bootstrapMajorVersion, id = this.$element.attr("id"); // 版本2中容器元素只能为div,版本3容器元素只能为ul if (version === 2 && !this.$element.is("div")) { throw "in Bootstrap version 2 the pagination must be a div element. Or if you are using Bootstrap pagination 3. Please specify it in bootstrapMajorVersion in the option"; } else if (version > 2 && !this.$element.is("ul")) { throw "in Bootstrap version 3 the pagination root item must be an ul element." } this.currentPage = 1; this.lastPage = 1; this.setOptions(options); this.initialized = true; }, //配置项,绑定事件、渲染页面 setOptions: function (options) { this.options = $.extend({}, (this.options || $.fn.bootstrapPaginator.defaults), options); this.totalPages = parseInt(this.options.totalPages, 10); this.numberOfPages = parseInt(this.options.numberOfPages, 10); if (options && typeof (options.currentPage) !== 'undefined') { this.setCurrentPage(options.currentPage); } this.listen(); this.render(); if (!this.initialized && this.lastPage !== this.currentPage) { this.$element.trigger("page-changed", [this.lastPage, this.currentPage]); } }, // 绑定事件监听函数,page-clicked事件触发onPageClicked方法,page-changed事件触发onPageChanged方法 // this.onPageClicked调用paginator类的方法,this.options.onPageClicked调用配置项中的方法 // listen: function () { this.$element.off("page-clicked"); this.$element.off("page-changed"); if (typeof (this.options.onPageClicked) === "function") { this.$element.bind("page-clicked", this.options.onPageClicked); } if (typeof (this.options.onPageChanged) === "function") { this.$element.on("page-changed", this.options.onPageChanged); } this.$element.bind("page-clicked", this.onPageClicked); }, destroy: function () { this.$element.off("page-clicked"); this.$element.off("page-changed"); this.$element.removeData('bootstrapPaginator'); this.$element.empty(); }, //根据页码显示状况和当前页进行渲染,trigger触发onPageChanged函数,传入当前页和前一次当前页两个参数 show: function (page) { this.setCurrentPage(page); this.render(); if (this.lastPage !== this.currentPage) { this.$element.trigger("page-changed", [this.lastPage, this.currentPage]); } }, //showNext、showPrev、showFirst、showLast页码显示状况 showNext: function () { var pages = this.getPages(); if (pages.next) { this.show(pages.next); } }, showPrevious: function () { var pages = this.getPages(); if (pages.prev) { this.show(pages.prev); } }, showFirst: function () { var pages = this.getPages(); if (pages.first) { this.show(pages.first); } }, showLast: function () { var pages = this.getPages(); if (pages.last) { this.show(pages.last); } }, //通过on方法向onPageItemClicked方法中的event.data传递参数,再通过trigger触发page-clicked事件,调用onPageClicked方法,实现参数传递 //onPageClicked修改页面显示状况,onPageChanged可以用来前后台的数据交互,参数为event,lastpage、currentpage onPageItemClicked: function (event) { var type = event.data.type, page = event.data.page; this.$element.trigger("page-clicked", [event, type, page]); }, onPageClicked: function (event, originalEvent, type, page) { var currentTarget = $(event.currentTarget); switch (type) { case "first": currentTarget.bootstrapPaginator("showFirst"); break; case "prev": currentTarget.bootstrapPaginator("showPrevious"); break; case "next": currentTarget.bootstrapPaginator("showNext"); break; case "last": currentTarget.bootstrapPaginator("showLast"); break; case "page": currentTarget.bootstrapPaginator("show", page); break; } }, // 根据版本号判断是否添加包裹元素ul,为该ul添加pagination类,设定大小、对齐方式 // 包裹元素根据first、next、prev、last、page类型,通过buildPageItem创建li、a子元素 render: function () { // 容器元素的类会被清空,需要优先记录,添加完pagination类后再放回 var containerClass = this.getValueFromOption(this.options.containerClass, this.$element), size = this.options.size || "normal", alignment = this.options.alignment || "left", pages = this.getPages(), listContainer = this.options.bootstrapMajorVersion === 2 ? $("<ul></ul>") : this.$element, listContainerClass = this.options.bootstrapMajorVersion === 2 ? this.getValueFromOption(this.options.listContainerClass, listContainer) : null, first = null, prev = null, next = null, last = null, p = null, i = 0; listContainer.prop("class", ""); listContainer.addClass("pagination"); switch (size.toLowerCase()) { case "large": case "small": case "mini": this.$element.addClass($.fn.bootstrapPaginator.sizeArray[this.options.bootstrapMajorVersion][size.toLowerCase()]); break; default: break; } if (this.options.bootstrapMajorVersion === 2) { switch (alignment.toLowerCase()) { case "center": this.$element.addClass("pagination-centered"); break; case "right": this.$element.addClass("pagination-right"); break; default: break; } } this.$element.addClass(containerClass); this.$element.empty(); if (this.options.bootstrapMajorVersion === 2) { this.$element.append(listContainer); listContainer.addClass(listContainerClass); } this.pageRef = []; if (pages.first) { first = this.buildPageItem("first", pages.first); if (first) { listContainer.append(first); } } if (pages.prev) { prev = this.buildPageItem("prev", pages.prev); if (prev) { listContainer.append(prev); } } for (i = 0; i < pages.length; i = i + 1) { p = this.buildPageItem("page", pages[i]); if (p) { listContainer.append(p); } } if (pages.next) { next = this.buildPageItem("next", pages.next); if (next) { listContainer.append(next); } } if (pages.last) { last = this.buildPageItem("last", pages.last); if (last) { listContainer.append(last); } } }, // 容器元素下插入li子元素,当前页添加active类,首页、前一页、后一页、尾页显示文本、提示框,绑定点击事件 buildPageItem: function (type, page) { var itemContainer = $("<li></li>"), itemContent = $("<a></a>"), text = "", title = "", //itemContainerClass记录当前页的激活状态 itemContainerClass = this.options.itemContainerClass(type, page, this.currentPage), itemContentClass = this.getValueFromOption(this.options.itemContentClass, type, page, this.currentPage), tooltipOpts = null; switch (type) { case "first": //判断是否显示跳转到首页,根据当前页是否首页进行判断 if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; } text = this.options.itemTexts(type, page, this.currentPage); title = this.options.tooltipTitles(type, page, this.currentPage); break; case "last": if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; } text = this.options.itemTexts(type, page, this.currentPage); title = this.options.tooltipTitles(type, page, this.currentPage); break; case "prev": if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; } text = this.options.itemTexts(type, page, this.currentPage); title = this.options.tooltipTitles(type, page, this.currentPage); break; case "next": if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; } text = this.options.itemTexts(type, page, this.currentPage); title = this.options.tooltipTitles(type, page, this.currentPage); break; case "page": if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; } text = this.options.itemTexts(type, page, this.currentPage); title = this.options.tooltipTitles(type, page, this.currentPage); break; } itemContainer.addClass(itemContainerClass).append(itemContent); // a元素中绑定onPageItemClicked事件,并通过on方法以及$.proxy方法传递参数,on方法的第三个参数是给event.data添加的参数 // 分页通过前后端以ajax形式传递数据的方式实现跳转 itemContent.addClass(itemContentClass).html(text).on("click", null, {type: type, page: page}, $.proxy(this.onPageItemClicked, this)); // 分页通过跳链接的方式实现跳转 if (this.options.pageUrl) { itemContent.attr("href", this.getValueFromOption(this.options.pageUrl, type, page, this.currentPage)); } // 提示默认采用浏览器自带提示框,也可以引进bootstrapTooltip插件实现提示框 if (this.options.useBootstrapTooltip) { tooltipOpts = $.extend({}, this.options.bootstrapTooltipOptions, {title: title}); itemContent.tooltip(tooltipOpts); } else { itemContent.attr("title", title); } return itemContainer; }, // 设置当前页,并记录上一次的当前页,避免用户重复点击同一页面触发事件 setCurrentPage: function (page) { if (page > this.totalPages || page < 1) { throw "Page out of range"; } this.lastPage = this.currentPage; this.currentPage = parseInt(page, 10); }, // 数组记录页码显示状况,数组的属性记录当前页,前一页,后一页,首页,尾页,总页数,显示页码数 getPages: function () { var totalPages = this.totalPages, pageStart = (this.currentPage % this.numberOfPages === 0) ? (parseInt(this.currentPage / this.numberOfPages, 10) - 1) * this.numberOfPages + 1 : parseInt(this.currentPage / this.numberOfPages, 10) * this.numberOfPages + 1,//calculates the start page. output = [], i = 0, counter = 0; pageStart = pageStart < 1 ? 1 : pageStart; for (i = pageStart, counter = 0; counter < this.numberOfPages && i <= totalPages; i = i + 1, counter = counter + 1) {//fill the pages output.push(i); } output.first = 1; if (this.currentPage > 1) { output.prev = this.currentPage - 1; } else { output.prev = 1; } if (this.currentPage < totalPages) { output.next = this.currentPage + 1; } else { output.next = totalPages; } output.last = totalPages; output.current = this.currentPage; output.total = totalPages; output.numberOfPages = this.options.numberOfPages; return output; }, // 配置项中有函数,将参数传入函数输出,无函数直接输出 getValueFromOption: function (value) { var output = null, args = Array.prototype.slice.call(arguments, 1); if (typeof value === 'function') { output = value.apply(this, args); } else { output = value; } return output; } }; //构造jquery插件 old = $.fn.bootstrapPaginator; $.fn.bootstrapPaginator = function (option) { var args = arguments, result = null; $(this).each(function (index, item) { var $this = $(item), data = $this.data('bootstrapPaginator'),//获取元素的data数据,该数据不会在页面上显示,不知何种泳衣??? options = (typeof option !== 'object') ? null : option; if (!data) { data = new BootstrapPaginator(this, options); $this = $(data.$element); $this.data('bootstrapPaginator', data); return; } if (typeof option === 'string') { if (data[option]) { result = data[option].apply(data, Array.prototype.slice.call(args, 1)); } else { throw "Method " + option + " does not exist"; } } else { result = data.setOptions(option); } }); return result; }; $.fn.bootstrapPaginator.sizeArray = { "2": { "large": "pagination-large", "small": "pagination-small", "mini": "pagination-mini" }, "3": { "large": "pagination-lg", "small": "pagination-sm", "mini": "" } }; $.fn.bootstrapPaginator.defaults = { containerClass: "", size: "normal", alignment: "left", bootstrapMajorVersion: 3, listContainerClass: "", itemContainerClass: function (type, page, current) { return (page === current) ? "active" : ""; }, itemContentClass: function (type, page, current) { return ""; }, currentPage: 1, numberOfPages: 5, totalPages: 1, pageUrl: function (type, page, current) { return null; }, onPageClicked: null, onPageChanged: null, useBootstrapTooltip: false, shouldShowPage: function (type, page, current) { var result = true; switch (type) { case "first": result = (current !== 1); break; case "prev": result = (current !== 1); break; case "next": result = (current !== this.totalPages); break; case "last": result = (current !== this.totalPages); break; case "page": result = true; break; } return result; }, itemTexts: function (type, page, current) { switch (type) { case "first": return "<<"; case "prev": return "<"; case "next": return ">"; case "last": return ">>"; case "page": return page; } }, tooltipTitles: function (type, page, current) { switch (type) { case "first": return "Go to first page"; case "prev": return "Go to previous page"; case "next": return "Go to next page"; case "last": return "Go to last page"; case "page": return (page === current) ? "Current page is " + page : "Go to page " + page; } }, bootstrapTooltipOptions: { animation: true, html: true, placement: 'top', selector: false, title: "", container: false } }; $.fn.bootstrapPaginator.Constructor = BootstrapPaginator; }(window.jQuery));