搜索

首页  >  问答  >  正文

jquery 求教:如何去思考一个JQ的组件封装?

如何去思考一个JQ的组件封装?想请教一个比较详细的思路,我自身在思考的时候对于这个学习没有一个太理想的思路。主要是在JS的代码结构规划上面。

比如:我有一个表格,里面放进了数量,名字,高度,宽度,等等一系列的数据,数据格式object,array,number,fn()等等各种都有。在外面调用这个组件时根据传入的数据将对应的信息显示出来。

这是一个别人封装的插件样例:

(function($ , undefined) {

    var Table = function (element, options) {
        this.$this = $(element);
        this.options = $.extend({}, $.fn.table.defaults, options);
        this.init();
    };
    // 使用proptotype给Table添加属性,
    Table.prototype = {
        constructor: Table,

        dataToObj: function(str){
            if(typeof str == "string" && str[0] == "&"){
                str = str.substring(1, str.length); 
            }
        
            if(typeof str == "string"){
                str = str.replace(/&/g,"','");
                str = str.replace(/=/g,"':'");
                str = "({'"+str +"'})";
                return eval(str); 
            }
        },

        init: function () {
            var options = this.options;
            if(!options.columns) return false;
            this.$this.html("");
            this.initTableHead();
            this.initTableBody(options.currentPage);
        },

        initTableHead: function(){
            var options = this.options,
                tableWrap = this.$this,
                attributesArr = [],
                theadStr = '<thead><tr class="'+options.hdBg+'">';

            for(var i=0, len=options.columns.length; i< len; i++){
                theadStr += '<th data-attribute="'+options.columns[i].dataIndex+'" width="'+(options.columns[i].width || "")+'">'+options.columns[i].title+'</th>';
                attributesArr.push(options.columns[i].dataIndex);
            }
            this.options.attributes = attributesArr;
            theadStr += '</tr></thead><tbody></tbody>';
            this.$this.append(theadStr);
        },

        initTableBody: function(currentPage){
            var that = this, options = this.options, data = null;
                data = this.dataToObj(options.data);
            $.ajax({
                type: "POST",
                dataType: "json",
                url: options.url,
                data: options.data,
                beforeSend: function(){
                    Common.showLoading();
                },
                timeout: options.timeout,  
                complete: function(XMLHttpRequest, textStatus){
                    if(textStatus == "timeout"){ Common.dialogTip({info: "请求超时,请重试!!!"}); }
                    Common.hideLoading();
                },
                success : function(result){
                    if(result.errorCode == "106"){
                        location.href= result.info + "?goto=" + location.href; 
                    }else if(result.success) {
                        var totalCount = result.total,
                            attributes = options.attributes,
                            tbodyWrap = that.$this.find("tbody"),
                            rowStr = "",
                            tbodyStr = "";
                        if(result.data.length > 0){
                             $.each(result.data,function(index, row){
                                 var rowStr="<tr>";
                                 for(var key in attributes){
                                    var tddata=(row[attributes[key]] || "");
                                    if(row[attributes[key]] === 0){
                                        tddata = "0";
                                    }
                                    //去除html标签,如果有的话
                                    var reg =new RegExp("<\/?[^>]*>");
                                    if(reg.test(tddata)){
                                        tddata =tddata.replace(/<[^>]+>/g,"");
                                    }
                                     rowStr +="<td>"+tddata+"</td>";
                                 }
                                 rowStr+="</tr>";
                                 tbodyStr += rowStr;
                             });
                              tbodyWrap.html(tbodyStr);
                              that.rendererTd(result.data);
                              //加载分页
                              if(options.pagingBar && result.data.length > 0){
                                  pageNo = data ? data.pageNo : 0;
                                  that.loadPagingBar(result.total, parseInt(currentPage || pageNo));
                              }
                        }else{
                            tbodyWrap.html('<tr><td colspan="'+options.columns.length+'" class="text-center">没有找到任何数据!!!</td></tr>');
                            $('#'+options.pagingBarId).html("");
                        }
                        if(typeof(options.callback) == 'function'){
                            options.callback(result, data)
                        }
                    }else {
                        that.dialogTip(result.info);
                    }
                }
              });
        },

        rendererTd: function(rowsData){
            var columns = this.options.columns,
                rowElem = null,
                rendererTd = null;
            this.$this.children("tbody").children("tr").each(function(index, elem){
                rowElem = $(elem);
                $.each(columns, function(i, item){
                    if(columns[i].renderer && typeof columns[i].renderer == "function"){
                        rendererTd = rowElem.children("td:eq("+i+")");
                        columns[i].renderer.call(rendererTd, rendererTd.text(), rowsData[index]);
                    }
                });

            });
            var onRendered = this.options.onRendered;
            if (onRendered && typeof(onRendered) == "function") {
                onRendered.call(this);
            }
        },

        loadPagingBar: function(total, currentPage){
            total = total || 0;
            currentPage = currentPage || 1;
            var that = this,
                options = this.options,
                totalPages = Math.ceil(total/options.pageSize),
                pageWrap = $('#'+options.pagingBarId);
            //console.log(total + "......" +totalPages);
            pageWrap.html('');
            pageWrap.html('<ul class="pagination pagination-sm" id="pager-ext" style="margin:7px 0 2px 0;"></ul>');
            pageWrap.find('#pager-ext').twbsPagination({
                totalPages:totalPages,
                visiblePages:options.visiblePages,
                startPage: currentPage,
                first: '第一页',
                prev: '上一页',
                next: '下一页',
                last: '最后页',
                onPageClick: function (event, page) {
                    if(typeof options.onPageClick == "function"){
                        var obj = options.onPageClick(event, page);
                        $.extend(that.options, obj);
                        that.initTableBody(page);
                    }
                }
            });
            pageWrap.data("currPage", currentPage);
            pageWrap.find('#pager-ext').append('<li class="last active disabled"><a href="#">共'+totalPages+' 页</a></li>');
            pageWrap.find('#pager-ext').append('<li class="last active disabled"><a href="#">总计 '+total+' 条</a></li>');
        },

        dialogTip: function(info){
            var dialogStr = '<div class="modal fade">'+
                              '<div class="modal-dialog">'+
                                '<div class="modal-content">'+
                                  '<div class="modal-header">'+
                                    '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>'+
                                    '<h4 class="modal-title">友情提示</h4>'+
                                  '</div>'+
                                  '<div class="modal-body text-overflow">'+info+
                                  '</div>'+
                                '</div>'+
                              '</div>'+
                            '</div>';
            var wrap = $(dialogStr);
            $("body").append(wrap);
            wrap.modal('show');
            wrap.find(".close").on("click", function(){
                wrap.modal('hide');
                $("body").removeClass("modal-open");
                wrap.remove();
            });
        }

    };

    // option 可以是对象或者是方法名
    // value option为方法名时的参数
    $.fn.table = function (option, value) {
        var methodReturn;

        var $set = this.each(function () {
            var $this = $(this),
                options = typeof option === 'object' && option,
                data = new Table(this, options);
            if (typeof option === 'string') {
                methodReturn = data[option](value);
            };
        });

        return methodReturn ? $set : methodReturn;
    };

    /*
     * columns = [{ title: '供货商来源', width: 150, dataIndex: 'c', renderer:function(value,obj){
     *           return value+':'+obj.d;
     *      }}]
     *
     * */
    $.fn.table.defaults = {
        url : "",
        data:"",
        pageSize:10,
        timeout: 10000,
        currentPage: 1,
        autoLoad:true,
        columns : null,
        pagingBar:true,
        hdBg:"success",
        pagingBarId: "paginationholder",
        visiblePages:7,
        onPageClick: null,
        onRendered: null,
        callback: null
    };
    // 将插件类暴露给外界:
    $.fn.table.Constructor = Table;

})(jQuery);


phpcn_u747phpcn_u7472838 天前1090

全部回复(2)我来回复

  • 数据分析师

    数据分析师2017-10-01 00:22:29

    jquery 求教:如何去思考一个JQ的组件封装?-PHP中文网问答-jquery 求教:如何去思考一个JQ的组件封装?-PHP中文网问答

    围观一下哦,学习一下。

    回复
    0
  • 阿神

    阿神2017-02-16 11:30:45

    (一)思考该组件在项目中的文件结构

    通俗讲就是,你的组件代码及资源文件(可能包括模板html、css、js、img甚至依赖其他的子组件等等..)放在项目中的哪里?根据实际项目大小及业务场景的区分,一般都会将组件文件独立并解耦。

    (二)你的组件主要实现什么功能,如何渲染页面?

    题主描述的组件主要有2个功能:

    根据调用时传入的数据进行数据过滤

    将过滤后的数据通过表格的方式渲染在视图上

    (三)应用层如何调用你的组件?

    比如将你的组件挂载在 window 对象上? 或是模块化调用?

    (四)组件中涉及的数据结构是怎样的?

    如何存储 数量,名字,高度,宽度,等等一系列的数据 对应于 不同的数据格式?怎样的结构方便遍历查询?

    (五)思考实现组件的具体编码逻辑

    正如题主所说的通过 jQuery 操作DOM,暴露应用层的接口,创建组件实例并渲染页面,并且在编码过程中可以通过模拟接口来模拟组件实例的生成。

    ps:当然,一般的组件也会涉及 网络请求的处理,项目本身的一些静态配置及公有方法的调用,同其他组件间的调用联系 等等问题。如果你的组件层拥有很多组件的话,同时也可以为他们定义一个统一的执行生命周期(比如,组件属性设置-渲染-事件绑定-销毁),这样方便其他组件层开发人员的编码及后期维护。

    总之围绕着 Don't repeat yourself. 的编码原则的话,你会发现你的组件们会越来越健壮并且越来越可维护、可拓展。


    回复
    0
  • 取消回复