话说,大家都知道jQuery Easyui的各种组件之间是有继承或者依赖关系的,那么大家是否真的理解这里提到的“继承”或者“依赖”的关系了?本文就这两个问题做较为全面的阐述,希望通过本文大家能对easyui的运作机制有更为透彻的理解。继承和依赖关系主要体现在下面三点:
我们以combo和validatebox组件的关系作为例子,combo的属性继承自validatebox。我们先看combo组件构造函数的代码:
/** * 1.3.2版本combo组件的构造函数 * @param {} options * @param {} param * @return {} */ $.fn.combo = function(options, param) { if (typeof options == "string") { return $.fn.combo.methods[options](this, param); } options = options || {}; return this.each(function() { var state = $.data(this, "combo"); if (state) { $.extend(state.options, options); } else { var r = _e(this); state = $.data(this, "combo", { //唯有此处有继承之嫌疑,可是丝毫看不出combo继承了validatebox什么属性啊,怎么回事呢。 options : $.extend({}, $.fn.combo.defaults,$.fn.combo.parseOptions(this), options), combo : r.combo, panel : r.panel, previousValue : null }); $(this).removeAttr("disabled"); } //... }); };
acombo组件的代码里,我们没有捕捉到combo组件继承validatebox组件属性的地方,但是对于这句代码我们还没有深究:
options : $.extend({}, $.fn.combo.defaults,$.fn.combo.parseOptions(this), options)
我们再来看看combo组件的属性解析器是如何定义的:
/**
* 看到了不?是不是心中暗喜,原来藏在这里。
* 我们看到combo组件的属性来自于以下几部分;
* 1.validatebox组件属性转换器转换解析dom获取到的属性(优先级最低);
* 2.公用属性转换器转换指定的几个属性(优先级次之);
* 3.写死的panelHeight,multiple,disabled,value(优先级最高)
* @param {} target
*/
$.fn.combo.parseOptions = function(target) {
var t = $(target);
return
$.extend(
{},
$.fn.validatebox.parseOptions(target),
$.parser.parseOptions(target,
["width", "height", "separator",
{
panelWidth : "number",
editable : "boolean",
hasDownArrow : "boolean",
delay : "number"
}
]),
{
panelHeight : (t.attr("panelHeight") == "auto"? "auto" : parseInt(t.attr("panelHeight")) || undefined),
multiple : (t.attr("multiple") ? true : undefined),
disabled : (t.attr("disabled") ? true : undefined),
value : (t.val() || undefined)
}
);
};
综合combo的构造函数和combo的属性转换器,我们最终可以得到,combo的属性的属性来源,可以用简单的用下图来表示:
到这里为止,我们对jQuery Easyui组件之间属性的继承方式已经大致理解。其中重点是其继承方式是使用的jQuert的extend函数实现的,所以要想彻底明白,必须对extend函数有足够的了解,当然了这超出了本篇文章的讨论范围,请大家自行翻阅资料。
在传统的面向对象语言中,事件这个概念并不存在jQuery Easyui的事件其实也就是属性,继承的原理跟属性的继承完全一样,只不过这个属性是个带有函数罢了,开发者可以定义这个函数。然而大多事件最终是通过javascript的call函数来触发的,我们那combo组件的onHidePanel事件来看:
跟传统面向对象的语言一样,jQuery Easyui组件间的方法也是可以继承的,那么方法又是怎样被继承的呢,我们拿combobox组件的构造函数来分析:
官方的API里面说,combobox组件的方法集成自combo组件,这个在combobox组件的构造函数中已经充分体现出来了,jQuery Easyui所谓的继承,只不过是它内部的一种实现方案,并不是真正意义上的“继承”。
同时我们还必须看到方法继承的特殊性,即对用承载combobox组件的target,肯定也承载了combo组件,要不然不可能调用combo组件的方法,所以combobox组件的初始化过程中一定也在target上初始化了combo组件,也就是说,在target上肯定同时存储了名为"combo"和"combobox"的对象:
这就好比combo是个汽车人里的“大黄蜂”的汽车状态,那么combobox绝对不是由若干汽车人组成的超级擎天柱,而仅仅是由“汽车状态”变成了“机器人”状态的大黄蜂,换汤不换药,这是方法能够继承的前提。
依赖关系不仅仅体现在“继承”上面,也现成在“组成”上面,所以个人概括地用“依赖” == “继承” + “组成”;这个表达式来表示有依赖关系的组件。
我们拿dialog,window,linkbutton三个组件的关系来举例说明:
dialog组件依赖window组件和linkbutton组件。dialog其实就是window,因为他们有方法上的继承;同时window内部有实例化了linkbutton组件。这就好比,“汽车态”的大黄蜂变成了“机器人”状态的大黄蜂,同时一条吉娃娃跳到了它的手掌心,这只吉娃娃就是linkbutton了。
事件的继承:
function hiddenPanel(target){
var opts = $.data(target, "combo").options;
var panel = $.data(target, "combo").panel;
panel.panel("close");
//用户可以自定义opts.onHidePanel这个函数
//在combo的内部方法中会在程序中的适当位置调用这个函数,并且将上下文设置为target
opts.onHidePanel.call(target);
}
方法的继承:
$.fn.combobox = function(options, params){
//如果构造函数第一个入参是字符串,则是方法调用。
if (typeof options == "string") {
//尝试到combobox组件中找这个方法
var caller = $.fn.combobox.methods[options];
if (caller) {
//如果找到了这个方法,则调用之
return caller(this, params);
}
else {
//如果没有找到,则调用combo组件的同名方法
return this.combo(options, params);
}
}
//...
};
$.data(target,'combobox')//能取到数据
$.data(target,'combo')//也能取到数据
依赖涵盖继承: