转载请注明出处Ext中文网(http://www.ajaxjs.com)。
ExtJS 3.3的下一个版本就是4.0。——什么!?您不知道?那就让我们为你展开新一段的 Ext 之旅吧!
一、渲染组件的方式
话说 ExtJS Roadmap(新版本线路图)其中重要的一项就是“Rearchitected component rendering system - smaller, faster and simpler than ever before”,重新编制组件的渲染架构,目标是比以前更快、更精、更容易!。——旧 Ext 的渲染方式不好吗?也不是,关键是没有一个统一的构建组件机制。一般来说,创建一个自定义 Ext UI 组件,等于是各个组件的组合,例如一个 toolbar+grid 的配搭。如果需要创建特殊的控件,譬如一张图片加一个
checkbox,Ext 里面就没有这样的组件,需要我们去定义一个、创建一个。于是我们就可以以 Ext.Component 为基类(superclass),通过Ext的继承(Ext.extend),定义新的 img 和 checkbox 组件,当然还是以HTML标签为基础控制。我们所做的,首先是描述新控件它的结构,这种控件的结构可以称作 DOM 结构,或简单一点 HTML 结构。具体工作一般是先是声明一个 div 或 autoEl,那往往都是 DOM Script(createElement()/appendElement()……)的方法,或者更“先进”的一种方式是按照“DomHelper”的结构写
HTML 的 JSON 形式。定义结构的过程同时也是分配属性的过程,例如这个 img 元素是几高、几宽都在里面作说明。一般称作是分配默认参数。还有就是预留数据接口的问题,比如 img 的 src 无法一早确定。再复杂的数据接口如何规划,就上升到“数据绑定”的层面了,当定义好结构和参数等接口,就形成一个特定组件类供调用。实例化组件类时,就会将结构、参数的、外观的样式等等都注入到页面 DOM 内存中(若“非延时加载”),成功的话就算完成了渲染。
尽管过去 Ext 还提出了组件生存周期的概念,可是它并不是一个创建组件的对象模型,较多的在回收事件句柄、修正组件内存泄漏时发挥的作用比较明显。对于一般构建组件而言,需要与浏览器原理更贴切、更直观(Straightforward)的 API 来支撑。或者说,针对创建自定义组件时的流程转向,提供一套围绕组件“结构/数据”、“行为/事件”、“外观/样式”这三大理论高点而实现的逻辑程序。新内容可能会很精彩,但不用急于揭开神秘的面纱,没有所谓的“神秘”,上面我们回忆一下过去是怎么创建组件的,就是为了可以与4.0新方法对比一下。
Ext 内部渲染的还是比较复杂的,在 Component/Container 的对象模型,大肆充分应用 override(或更严格地表述,属于模式中的 Template 模式),又灵活地显示生命调用父类方法,远不如 overload 一个个方法清楚,已经是足够复杂了。详细的介绍可参考《ExtJS3详解与实践》的第四章内容。
是不是一定要了解 Ext 内部渲染才能写组件?不见得,因为 Ex t就是立足要避开这些复杂性,我们理解怎么有效率工作就足够了。小弟这里说多点嘛~只是想学人家抛砖引玉,呵呵。闲话休提,下面立刻介绍4.0出现的三个新的配置项参数(config items),它们是 renderTpl:String/Ext.XTemplate、renderSelector:String 和 renderData:Object。
二、介绍 renderTpl
ExtJS4 新版所带来的改进,其中之一是改变了渲染组件所依托的 div 结构。div 结构定义在Ext.Component.renderTpl(渲染模板)中。该组件是什么结构的,就会在 renderTpl 中反映出来。创建组件时,renderTpl 可以输入字符串,其字符串会作为构造器的参数送入 Ext.XTemplate 形成模板对象,从而借助该模板对象的属性和方法获得对组件结构的控制能力。Ext 的模板类是一个功能非常强大类,可支持子模板、模板表达式等的功能。此处的模板就是勾勒整个组件的骨架脉络。
打开源码Component.js,renderTpl一项可是除了一个"div"什么都没有了。因为这是Component基类,具体内容需要特定的子类所决定,当前就是这个div而已了。但应当指出,哪怕是一个什么内容都没有的Ext.Component,也一定会有Ext.Component类所赋予它的默认属性及其属性值。首先分派一个独一无二的id标识,保证了各个组件之间不会命名冲突,否则获取组件引用时会获取不正确;其次是组件的基本类,即<div class="cls1 cls2 cls2" ……></div>。渲染过程必须分配好这些基本类,包括cls、cmpCls、baseCls和ui。
当自定义新Component时,可以覆盖原有的renderTpl:'div'配置项属性,达到新建组件结构之目的。比如上一个“一张图片加一个checkbox的控件”的例子,就是:……
renderTpl:'<div><img src="afoo.jpg" mce_src="afoo.jpg" /><input type="checkbox" /></div>'
……
总之,可以预见的是,越复杂的组件伴随着越复杂的结构,因此必须谨记不时进行适当的优化。
这里顺便插一点。我们知道,Ext渲染的组件过程中生成大量的 HTML 标签,成为组件的“骨架(skeleton)”。虽然都是通过脚本生成这些 divs,不需要逐个 div 去手写,但是对性能而言毕竟只会加重负荷。创建一个普通的面板 Panel,底下起码有4~6层的 div,每层 div 都有特定的功能。同时,大量 Markup 的出现也会增加调试的困难。用户如果安装有 firebug 调试工具,打开“HTML”观察,就会看到一层层 div。曾经有资深 Widget 作者看到过如此复杂的HTML当场感叹Ext怎么不节省一下。
刚才的renderTpl的内容是写死的,仅作演示用,完整的一个Ext JS4.0组件创建方法如下:
IconComponent = Ext.extend(Ext.Component, {
iconCls: 'myIcon',
renderTpl: '<img alt="" src="{blank}" mce_src="{blank}" class="{iconCls}"/>',
initComponent: function() {
Ext.applyIf(this.renderData, {
blank: Ext.BLANK_IMAGE_URL,
iconCls: this.iconCls
});
Ext.applyIf(this.renderSelectors, {
iconEl: '.' + this.iconCls
});
IconComponent.superclass.initComponent.call(this);
},
changeIconCls: function(newIconCls) {
if (this.rendered) {
this.iconEl.replaceClass(this.iconCls, newIconCls);
}
this.iconCls = newIconCls;
}
});
三、renderData和renderSelector
有了 renderSelectors 不仅可以允许我们快捷地获取组件对象,而且可以比较清晰地掌握关键的内部结构,排除一些不必要的 Tags。通过指定 renderSelectors 为具体的 class 属性,任何一个组件的实例,都可以借助这个 renderSelectors 的寻址来找到。例如组件 body 的 renderSelectors 默认为 x-panel-body。
既然明确了结构,那么接下来绑定内容实体应该是很容易的事情了。如果不要写死结构的内容,我们可以通过读写 Ext.Component.renderData 配置项为组件提供数据内容。只要在 Ext.Component.renderData 上加入了新的数据,都会视作为组件的内容数据,例如上例 {blank} 变为 Ext.BLANK_IMAGE_URL,iconCls变为'myIcon';只要在 Ext.Component.renderSelectors 上定义了任何一个字段,都会视作 Ext.Element
类型的引用,所以上例中我们才可以使用“this.iconEl.replaceClass(this.iconCls, newIconCls);”替换样式。
另外,如果要对 renderTpl 里的某个 HTML 元素登记事件,利用 renderSelector 获取目标 HTML 元素也是一个不错的主意。
关于 this.renderSelectors.iconEl 怎么变为 this.iconEl 的原理过程,原来也是很容易理解的。见 Component.js 第782行:
……
applyRenderSelectors: function() {
var selectors = this.renderSelectors || {},
el = this.el.dom,
selector;
for (selector in selectors) {
if (!selectors.hasOwnProperty(selector)) {
continue;
}
this[selector] = Ext.get(Ext.DomQuery.selectNode(selectors[selector], el));
}
},
……
四、小结
新 ExtJS4发布之后,大家看到源码,那时应该会发现新的组件均会按照这种方式去定义的。采用新模式的组件是否真的会更利于组件的创建?4.0 尚在翘首期盼中,暂无结论,咱们拭目以待……
转载请注明出处Ext中文网(http://www.ajaxjs.com)。