如何去思考一个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">×</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);
数据分析师2017-10-01 00:22:29
jquery アドバイスを求めています: JQ コンポーネントのカプセル化についてどのように考えればよいですか? -PHP 中国語 Web サイト Q&A-jquery アドバイスを求めています: JQ コンポーネントのカプセル化についてどのように考えればよいですか? -PHP中国語サイトQ&A
ぜひ見て学んでください。
阿神2017-02-16 11:30:45
(一)思考该组件在项目中的文件结构
通俗讲就是,你的组件代码及资源文件(可能包括模板html、css、js、img甚至依赖其他的子组件等等..)放在项目中的哪里?根据实际项目大小及业务场景的区分,一般都会将组件文件独立并解耦。
(二)你的组件主要实现什么功能,如何渲染页面?
题主描述的组件主要有2个功能:
根据调用时传入的数据进行数据过滤
将过滤后的数据通过表格的方式渲染在视图上
(三)应用层如何调用你的组件?
比如将你的组件挂载在 window 对象上? 或是模块化调用?
(四)组件中涉及的数据结构是怎样的?
如何存储 数量,名字,高度,宽度,等等一系列的数据 对应于 不同的数据格式?怎样的结构方便遍历查询?
(五)思考实现组件的具体编码逻辑
正如题主所说的通过 jQuery 操作DOM,暴露应用层的接口,创建组件实例并渲染页面,并且在编码过程中可以通过模拟接口来模拟组件实例的生成。
ps:当然,一般的组件也会涉及 网络请求的处理,项目本身的一些静态配置及公有方法的调用,同其他组件间的调用联系 等等问题。如果你的组件层拥有很多组件的话,同时也可以为他们定义一个统一的执行生命周期(比如,组件属性设置-渲染-事件绑定-销毁),这样方便其他组件层开发人员的编码及后期维护。
总之围绕着 Don't repeat yourself. 的编码原则的话,你会发现你的组件们会越来越健壮并且越来越可维护、可拓展。