Parser
parser模塊是easyloader第一個加載的模塊
在前面的筆記中,我們分析了easyloader源代碼,知道easyui加載模塊組件可以有2種方式:
- 通過設置class屬性的方式
- 使用JavaScript的方式進行渲染
這本質上是通過parser解析器來實現的,一般是自動觸發完成整個頁面的解析。
parser主要作用
parser自動渲染:
最主要的運用場景:
只要我們書寫相應的class,easyui就能成功的渲染頁面。
這是因爲解析器在默認情況下,會在dom加載完成的時候($(docunment).ready)
被調用,而且是渲染整個頁面。parser解析器手動渲染:
需要手動調用的情況是:
當頁面已經加載完成,但是此時我們使用js生成的DOM中包含了easyui支持的class,並且我們也有將其渲染成easyui組件的需求。在這種情況下就需要手動調用parser
<div class="easyui-accordion" id="tt">
<div title="title1">1</div>
<div title="title2">2</div>
</div>
當上面代碼的生成是在easyui渲染界面完成之後,easyui不會一直監聽頁面,所以該段代碼不會被渲染成“手風琴DIV”的樣式。
此時就需要我們手動去渲染了。
注意:
解析目標位指定DOM的所有子孫元素,不包括DOM本身。
$parser.parser($('tt').parent())
並非
$.parser.parse($('#tt'));
儘量不要多次解析同一個DOM元素(ID):頁面初始化就已經主動渲染過dom節點了,你再次手動解析該dom節點時該dom已經被parser重構,得到的DOM就並非是你料想的結果,該方式應該儘量避免。
- 用法總結
$.parser.parse(); // 不帶參數,默認解析該頁面中所有被定義爲easyui組件的節點就是解析整個頁面
$.parser.parse('#cc'); // 帶一個jquery選擇器,使用這種方式我們可以單獨解析局部的easyui組件節點
注意:
上面的id不能是爲當前組件的id,必須爲當前組件父容器的id。也就是說這個jquery選擇器必須是解析組件的父級以上的節點,潛臺詞就是這個查找出來的節點相當於一個容器,它只會解析容器裏面的內容。
<div id="cc">
<div id="Window" class="easyui-window"></div>
</div>
$.parser.parse('#cc');
這麼使用id爲Window的節點纔會正常。
$.parser.parse();
不傳參是解析頁面中所有定義爲easyui組件的節點。
- 特性
名稱 | 類型 | 描述 | 默認值 |
---|---|---|---|
$.parser.auto | boolean | 定義是否自動解析easyui組件 | true |
- 事件
名稱 | 參數 | 描述 |
---|---|---|
$.parser.onComplete | context | 當解析器完成解析動作的時候觸發 |
- 方法
名稱 | 參數 | 描述 |
---|---|---|
$.parser.parse | context | 解析easyui組件 |
parser源代碼閱讀分析筆記:
源代碼很多,只截取了部分主要的放了上來
/**
* parser模塊主要作用是解析頁面中easyui的控件
*/
$.parser = {
//是否自動解析
auto : true,
//渲染完成後會觸發onComplete事件,若該事件綁定了處理函數,則每次調用parser渲染DOM後都會觸發一次該事件綁定的處理函數
onComplete : function(_b) {
},
//plugins屬性枚舉出了所有可以被parse解析的控件組件名稱
plugins : [ "draggable", "droppable", "resizable", "pagination",
"tooltip", "linkbutton", "menu", "menubutton", "splitbutton",
"switchbutton", "progressbar", "tree", "textbox",
"passwordbox", "filebox", "combo", "combobox", "combotree",
"combogrid", "combotreegrid", "numberbox", "validatebox",
"searchbox", "spinner", "numberspinner", "timespinner",
"datetimespinner", "calendar", "datebox", "datetimebox",
"slider", "layout", "panel", "datagrid", "propertygrid",
"treegrid", "datalist", "tabs", "accordion", "window",
"dialog", "form" ],
/**
* function(context) 解析函數
* 實現渲染DOM的核心方法,傳入參數爲DOM對象,其實也就是某個DOM塊,不傳入參的話,則是對整個頁面進行渲染。
*/
parse : function(_c) {
var aa = [];
for (var i = 0; i < $.parser.plugins.length; i++) {
// _d=name , 控件名字
var _d = $.parser.plugins[i];
// 查找指定DOM下的特定的easyui組件,也就是查找class爲easyui-控件名字的jq對象,即以_c爲上下文查找_d組件對應的DOM對象,比如:easyui-layout._c爲空的話,則在整個document爲上下文
var r = $(".easyui-" + _d, _c);
if (r.length) {
if (r[_d]) { //如果有這個對象
/**
* 調用plugins某個裏_d組件對象的類似於構造函數的那個匿名函數(就把它叫做構造函數了。。僅僅是因爲叫起來方便)
* 上下文就是r對象自身了,也就是構造函數裏面使用的this
* 這個地方容易暈,r[_d]其實是function類型,其實也就是各個組件對應的構造函數
* 例如panel組件的代碼裏有這樣的定義:
* $.fn.panel = function(jq, options){...}
* jQuery擴展fn的話等於擴展了全局方法到jQuery對象上,也就是所有的jQuery對象都具備了panel這個方法
* 如果沒有使用easyloader的話,r對應其實已經具備了easyui所有組件的構造函數
*/
r.each(function() {
$(this)[_d]($.data(this, "options") || {});
});
}
else { //這個else分支也只有在使用easyloader的時候纔會調用到
aa.push({
name : _d,
jq : r
});
}
}
}
if (aa.length && window.easyloader) {
var _e = [];
for (var i = 0; i < aa.length; i++) {
_e.push(aa[i].name);
}
easyloader.load(_e, function() {
for (var i = 0; i < aa.length; i++) {
var _f = aa[i].name;
var jq = aa[i].jq;
//調用組件的構造函數
jq.each(function() {
$(this)[_f]($.data(this, "options") || {});
});
}
$.parser.onComplete.call($.parser, _c);
});
}
else {
/**
* 調用綁定的onComplete事件
* 傳入參數爲上下文_c
* 目的就是把_c作爲參數傳給onComplete事件綁定的函數來處理程序
*/
$.parser.onComplete.call($.parser, _c);
}
},
//公用的屬性轉換器
parseValue : function(_10, _11, _12, _13) {
_13 = _13 || 0;
var v = $.trim(String(_11 || ""));
var _14 = v.substr(v.length - 1, 1);
if (_14 == "%") {
v = parseInt(v.substr(0, v.length - 1));
if (_10.toLowerCase().indexOf("width") >= 0) {
v = Math.floor((_12.width() - _13) * v / 100);
} else {
v = Math.floor((_12.height() - _13) * v / 100);
}
} else {
v = parseInt(v) || undefined;
}
return v;
},
parseOptions : function(_15, _16) {
var t = $(_15);
var _17 = {};
var s = $.trim(t.attr("data-options"));
if (s) {
if (s.substring(0, 1) != "{") {
s = "{" + s + "}";
}
_17 = (new Function("return " + s))();
}
$.map([ "width", "height", "left", "top", "minWidth", "maxWidth",
"minHeight", "maxHeight" ], function(p) {
var pv = $.trim(_15.style[p] || "");
if (pv) {
if (pv.indexOf("%") == -1) {
pv = parseInt(pv);
if (isNaN(pv)) {
pv = undefined;
}
}
_17[p] = pv;
}
});
if (_16) {
var _18 = {};
for (var i = 0; i < _16.length; i++) {
var pp = _16[i];
if (typeof pp == "string") {
_18[pp] = t.attr(pp);
} else {
for ( var _19 in pp) {
var _1a = pp[_19];
if (_1a == "boolean") {
_18[_19] = t.attr(_19) ? (t.attr(_19) == "true")
: undefined;
} else {
if (_1a == "number") {
_18[_19] = t.attr(_19) == "0" ? 0
: parseFloat(t.attr(_19))
|| undefined;
}
}
}
}
}
$.extend(_17, _18);
}
return _17;
}
};
//文檔準備好後,根據$.parser.auto的設置來決定是否自動渲染
$(function() {
var d = $(
"<div style=\"position:absolute;top:-1000px;width:100px;height:100px;padding:5px\"></div>")
.appendTo("body");
$._boxModel = d.outerWidth() != 100;
d.remove();
d = $("<div style=\"position:fixed\"></div>").appendTo("body");
$._positionFixed = (d.css("position") == "fixed");
d.remove();
if (!window.easyloader && $.parser.auto) {
$.parser.parse();
}
});
//擴展_outerWidth方法到jQuery對象上,用於兼容IE這種不是正規盒子模型的瀏覽器
$.fn._outerWidth = function(_1b) {
if (_1b == undefined) {
if (this[0] == window) {
return this.width() || document.body.clientWidth;
}
return this.outerWidth() || 0;
}
return this._size("width", _1b);
};
//擴展_outerHeight方法到jQuery對象上,用於兼容IE這種不是正規盒子模型的瀏覽器
$.fn._outerHeight = function(_1c) {
if (_1c == undefined) {
if (this[0] == window) {
return this.height() || document.body.clientHeight;
}
return this.outerHeight() || 0;
}
return this._size("height", _1c);
};
$.fn._scrollLeft = function(_1d) {
if (_1d == undefined) {
return this.scrollLeft();
} else {
return this.each(function() {
$(this).scrollLeft(_1d);
});
}
};
$.fn._propAttr = $.fn.prop || $.fn.attr;
$.fn._size = function(_1e, _1f) {
if (typeof _1e == "string") {
if (_1e == "clear") {
return this.each(function() {
$(this).css({
width : "",
minWidth : "",
maxWidth : "",
height : "",
minHeight : "",
maxHeight : ""
});
});
} else {
if (_1e == "fit") {
return this.each(function() {
_20(this, this.tagName == "BODY" ? $("body") : $(this)
.parent(), true);
});
} else {
if (_1e == "unfit") {
return this.each(function() {
_20(this, $(this).parent(), false);
});
} else {
if (_1f == undefined) {
return _21(this[0], _1e);
} else {
return this.each(function() {
_21(this, _1e, _1f);
});
}
}
}
}
} else {
return this.each(function() {
_1f = _1f || $(this).parent();
$.extend(_1e, _20(this, _1f, _1e.fit) || {});
var r1 = _22(this, "width", _1f, _1e);
var r2 = _22(this, "height", _1f, _1e);
if (r1 || r2) {
$(this).addClass("easyui-fluid");
} else {
$(this).removeClass("easyui-fluid");
}
});
}