深入學習jquery原始碼之繼承框架的實現
阿新 • • 發佈:2018-12-23
深入學習jquery原始碼之繼承框架的實現
繼承框架的實現
/* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. */ // Inspired by base2 and Prototype (function(){ //initializing是為了解決我們之前說的繼承導致原型有多餘引數的問題。當我們直接將父類的例項賦值給子類原型時。是會呼叫一次父類的建構函式的。所以這邊會把真正的構造流程放到init函式裡面,通過initializing來表示當前是不是處於構造原型階段,為true的話就不會呼叫init。 //fnTest用來匹配程式碼裡面有沒有使用super關鍵字。對於一些瀏覽器`function(){xyz;}`會生成個字串,並且會把裡面的程式碼弄出來,有的瀏覽器就不會。`/xyz/.test(function(){xyz;})`為true代表瀏覽器支援看到函式的內部程式碼,所以用`/\b_super\b/`來匹配。如果不行,就不管三七二十一。所有的函式都算有super關鍵字,於是就是個必定匹配的正則。 var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; // The base Class implementation (does nothing) // 超級父類 this.Class = function(){}; // Create a new Class that inherits from this class // 生成一個類,這個類會具有extend方法用於繼續繼承下去 Class.extend = function(prop) { //保留當前類,一般是父類的原型 //this指向父類。初次時指向Class超級父類 var _super = this.prototype; // Instantiate a base class (but only create the instance, // don't run the init constructor) //開關 用來使原型賦值時不呼叫真正的構成流程 initializing = true; var prototype = new this(); initializing = false; // Copy the properties over onto the new prototype for (var name in prop) { // Check if we're overwriting an existing function //這邊其實就是很簡單的將prop的屬性混入到子類的原型上。如果是函式我們就要做一些特殊處理 prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ //通過閉包,返回一個新的操作函式.在外面包一層,這樣我們可以做些額外的處理 return function() { var tmp = this._super; // Add a new ._super() method that is the same method // but on the super-class // 呼叫一個函式時,會給this注入一個_super方法用來呼叫父類的同名方法 this._super = _super[name]; // The method only need to be bound temporarily, so we // remove it when we're done executing //因為上面的賦值,是的這邊的fn裡面可以通過_super呼叫到父類同名方法 var ret = fn.apply(this, arguments); //離開時 儲存現場環境,恢復值。 this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } // 這邊是返回的類,其實就是我們返回的子類 function Class() { // All construction is actually done in the init method if ( !initializing && this.init ) this.init.apply(this, arguments); } // 賦值原型鏈,完成繼承 Class.prototype = prototype; // 改變constructor引用 Class.prototype.constructor = Class; // 為子類也新增extend方法 Class.extend = arguments.callee; return Class; }; })();
初始化Class
(function(scope){ var ListPager = Class.extend({ init: function(){}, render: function(){ var _self = this; //彈出卡片介面的大小[60%,80%] _self.cardSize = _self.cardSize || ['80%','80%']; //彈出卡片介面方式:頁面層(這裡content是一個普通的String):1;iframe層(content是一個URl):2 _self.cardPopStyle = _self.cardPopStyle || LayuiPopStyle.LAYUI_IFRAME_LAYER; _self.tableId = _self.container + "." + _self.primaryKey; //plugins 這個可以不傳,但是請不要傳空陣列過來 var plugins = _self.plugins || ['table','form']; var p = _self.assemblyFormPrams(); //利用layui 繪製列表 ( url : _self.url+"?decAjaxReq=yes", 給ajax請求加密) layui.use(plugins, function(){ var option = $.extend({elem: "#" + _self.container, url : _self.url, cols: _self.title, method: RequestMethod.METHOD_POST, id : _self.tableId, even: true, page: true, //是否顯示分頁 pageNum: 1, limit: _self.pageSize, //每頁預設顯示的數量 limits:[5,10,15,20,30]}, _self.layOption); //展示已知資料 layui.table.render(option); //渲染部分layui元件 _self.initLayuiPlugin(); //監聽工具條 layui.table.on('tool(' + _self.container + ')', function(obj){ //注:tool是工具條事件名,test是table原始容器的屬性 lay-filter="對應的值" if(_self.hookMethod && $.isFunction(_self.hookMethod)){ _self.hookMethod(obj); //回撥 子類中的 鉤子方法 } }); //複選框事件選中以後回撥 layui.table.on('checkbox(' + _self.container + ')', function(obj){ if(_self.tableAfterChecked && $.isFunction(_self.tableAfterChecked)){ _self.tableAfterChecked(obj); //回撥 子類中的 鉤子方法 } }); }); //介面繪製完成, 初始化介面事件 _self.initEvent(); }, initLayuiPlugin: function(){ var _self = this; }, initEvent: function(){ var _self = this; //列表 增刪改查 $("div[name='listBtns'] button").unbind('click').bind('click', function(){ var action = "_self." + $(this).attr("action"); eval(action); }); //列表查詢、重置 $("div button[type='button']",$("#" + _self.container + "-QueryForm")) .unbind('click') .bind('click', function(){ var action = "_self." + $(this).attr("action"); eval(action); }); }, assemblyFormPrams: function(){ //組裝列表模糊查詢表單資料 var _self = this; var formParam = $("#" + _self.container + "-QueryForm").serializeArray(), reqParam = {}; for(var o in formParam){ if(formParam[o]["name"]){ reqParam[formParam[o]["name"]] = formParam[o]["value"]; } } return reqParam; }, listQuery: function(){ var _self = this; layui.table.reload(_self.tableId, { where: _self.assemblyFormPrams() }); }, /** * 獲取選中的資料 */ getSelectRows: function(){ var checkStatus = layui.table.checkStatus(this.tableId); return checkStatus.data; }, getSelectIds: function(){ var data = this.getSelectRows(); var ids = []; if($.isEmptyArray(data)) return ids; for(var i = 0; i < data.length; i++){ ids.push(data[i][this.primaryKey]); } return ids; }, view: function(curDom, event){ var _self = this; var data = _self.getSelectRows(); if (data.length != 1) { layer.msg("請選中一條資料進行檢視"); return; } var url = $(curDom).attr("url") + "?act=" + WebConst.READ + "&entityId=" + data[0][_self.primaryKey]; var title = $(curDom).attr("title"); var layIndex = layer.open({ type: this.cardPopStyle, title: title, maxmin: true, shadeClose: true, //開啟遮罩關閉 area : this.cardSize, content: this.cardPopStyle == LayuiPopStyle.LAYUI_CONTENT_LAYER ? $.loadHtml(url) : url, success: function(layero){ layero = _self.cardPopStyle == LayuiPopStyle.LAYUI_CONTENT_LAYER ? layero : layer.getChildFrame('body', layIndex); if(_self.cardPopStyle == LayuiPopStyle.LAYUI_CONTENT_LAYER){ layero.setValues(data[0]); } layui.form.render(); } }); }, add: function(curDom, event){ var _self = this; //新增之前回調函式 if(_self.beforeAdd && $.isFunction(_self.beforeAdd)){ _self.beforeAdd(); } var url = $(curDom).attr("url") + "?act=" + WebConst.ADD; var title = $(curDom).attr("title"); layer.open({ type: this.cardPopStyle, title: title, area: this.cardSize, maxmin: true, shadeClose: false, //開啟遮罩關閉 content: this.cardPopStyle == LayuiPopStyle.LAYUI_CONTENT_LAYER ? $.loadHtml(url) : url, success : function(layero){ layui.form.render(); }, end: function(){ //銷燬列表回撥方法 layui.table.reload(_self.tableId) if(_self.closeCard && $.isFunction(_self.closeCard)){ return _self.closeCard(); } return false; }, cancel: function(){ } }); }, edit: function(curDom, event){ var _self = this; var data = _self.getSelectRows(); if (data.length != 1) { layer.msg("請選中一條資料進行修改"); return; } //修改之前回調函式 if(_self.beforeUpd && $.isFunction(_self.beforeUpd)){ _self.beforeUpd(); } var url = $(curDom).attr("url") + "?act=" + WebConst.EDIT + "&entityId=" + data[0][_self.primaryKey]; var title = $(curDom).attr("title"); var layIndex = layer.open({ type: this.cardPopStyle, title: title, maxmin: true, shadeClose: false, //開啟遮罩關閉 area : this.cardSize, content: this.cardPopStyle == LayuiPopStyle.LAYUI_CONTENT_LAYER ? $.loadHtml(url) : url, success: function(layero){ layero = _self.cardPopStyle == LayuiPopStyle.LAYUI_CONTENT_LAYER ? layero : layer.getChildFrame('body', layIndex); if(_self.cardPopStyle == LayuiPopStyle.LAYUI_CONTENT_LAYER){ layero.setValues(data[0]); layui.form.render(); } }, end: function(){ //銷燬列表回撥方法 layui.table.reload(_self.tableId) if(_self.closeCard && $.isFunction(_self.closeCard)){ return _self.closeCard(); } return false; }, cancel: function(){ //點選左上角關閉按鈕回撥方法 if(_self.cardPopStyle == LayuiPopStyle.LAYUI_IFRAME_LAYER){ //從列表呼叫卡片頁面資料 var frameId = document.getElementById('layui-layer' + layIndex).getElementsByTagName("iframe")[0].id, closeCallback = $('#'+frameId)[0].contentWindow.beforeClose; if(closeCallback && $.isFunction(closeCallback)){ return closeCallback(); } } } }); }, del: function(curDom, event){ var _self = this; var data = _self.getSelectIds(); if(data.length == 0){ layer.msg("請至少選擇一條需要刪除的資料"); return; } var url = $(curDom).attr("url") + "?act=" + WebConst.DELETE; layer.confirm('確定刪除嗎', function(index){ layer.close(index); $.ajaxReq(url,$.toJSON(data),function(){ layui.table.reload(_self.tableId) }); }); } }); scope.ListPager = ListPager; })(window);
繼承的實現
ShowPipeList = ListPager.extend({ init : function(container, primaryKey, url){ debugger; //列表容器 this.container = container; //主鍵欄位 this.primaryKey = primaryKey; //資料請求地址 this.url = url; //介面需要引用的外掛 this.plugins = ['table', 'element', 'form', 'laydate', 'layer','carousel']; // //彈出卡片介面的大小[60%,80%] // this.cardSize = ['100%','100%']; // //彈出卡片介面方式:頁面層(這裡content是一個普通的String):1;iframe層(content是一個URl):2 this.cardPopStyle = 2; //每頁大小 this.pageSize = 5; //列表頭 this.title = [[ {field: 'startTime', title: '開始時間', width: 160}, {field: 'endTime', title: '結束時間', width: 160}, ]]; //外掛是基於layui封裝的, layOption是對layui的引數擴充套件(具體api參照layui屬性) this.layOption = { }; }, initLayuiPlugin: function(){ this._super(); var table = layui.table; var laydate = layui.laydate; //時間選擇器 laydate.render({ elem: '#test5' ,type: 'time' ,theme: '#050a3c' }); laydate.render({ elem: '#test6' ,type: 'time' ,theme: '#050a3c' }); }, initEvent: function(){ this._super(); //TODO 父類僅僅綁定了工具條通用按鈕事件, 如有其他事件請在這裡定義 }, hookMethod:function(obj){ var data = obj.data, url = CONTEXT_PATH + '/cusviews/pipe/listPipePoint'; var param = { cobwebId : data.cobwebId } var retData = $.getData(url,param); } }); $(function(){ var url = CONTEXT_PATH + '/cusviews/pipe/listPipe'; var showPipeList = new ShowPipeList("pipeList", "cobwebId", url); showPipeList.render(); $(".tc_box .cbar").scrollBar(); })
繼承實現的過程