话说,大家都知道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");
- }
- //...
- });
- };
combo组件的代码里,我们没有捕捉到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事件来看:
- 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);
- }
方法的继承:
跟传统面向对象的语言一样,jQuery Easyui组件间的方法也是可以继承的,那么方法又是怎样被继承的呢,我们拿combobox组件的构造函数来分析:
- $.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);
- }
- }
- //...
- };
官方的API里面说,combobox组件的方法集成自combo组件,这个在combobox组件的构造函数中已经充分体现出来了,jQuery Easyui所谓的继承,只不过是它内部的一种实现方案,并不是真正意义上的“继承”。
同时我们还必须看到方法继承的特殊性,即对用承载combobox组件的target,肯定也承载了combo组件,要不然不可能调用combo组件的方法,所以combobox组件的初始化过程中一定也在target上初始化了combo组件,也就是说,在target上肯定同时存储了名为"combo"和"combobox"的对象:
- $.data(target,'combobox')//能取到数据
- $.data(target,'combo')//也能取到数据
这就好比combo是个汽车人里的“大黄蜂”的汽车状态,那么combobox绝对不是由若干汽车人组成的超级擎天柱,而仅仅是由“汽车状态”变成了“机器人”状态的大黄蜂,换汤不换药,这是方法能够继承的前提。
依赖涵盖继承:
依赖关系不仅仅体现在“继承”上面,也现成在“组成”上面,所以个人概括地用“依赖” == “继承” + “组成”;这个表达式来表示有依赖关系的组件。
我们拿dialog,window,linkbutton三个组件的关系来举例说明:
dialog组件依赖window组件和linkbutton组件。dialog其实就是window,因为他们有方法上的继承;同时window内部有实例化了linkbutton组件。这就好比,“汽车态”的大黄蜂变成了“机器人”状态的大黄蜂,同时一条吉娃娃跳到了它的手掌心,这只吉娃娃就是linkbutton了。