bootstrap-paginator源码解读

 

收获:

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 "&lt;&lt;";
            case "prev":
                return "&lt;";
            case "next":
                return "&gt;";
            case "last":
                return "&gt;&gt;";
            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));

 

你可能感兴趣的:(bootstrap-paginator源码解读)