简介
前面讲过JS代码中如何实现模板,我们在实现控件的时候,每个控件初始化时都需要有默认的html,如果这些html都是固定的,那么当需求发生变化或者用到其他项目时,这个控件的迁移成本就会非常大,所以我们在设计控件的时候,就应该分析那些地方应该使用模板。
分析
控件有自己的生命周期,控件上显示的html和CSS一般情况下:
- 初始化时创建
- 状态发生改变时变化
本文关注的是控件初始化创建控件DOM时需要的模板,以及模板跟初始化传入变量之间的关系。控件的生命周期,前面曾经讲过,跟本文相关的是 createDom 和 renderUI
- createDom 就是控件创建自己的DOM结构
- renderUI 是控件根据一些配置项设置一些DOM的状态,以及生成渲染子控件
我们在考虑控件使用模板时,发现控件的模板对于菜单、列表这一类控件更为有用,这一类控件都是父控件包含多个同类的子控件,例如
l 一个菜单包含多个菜单项,
l 一个列表包含多个列表项
如果菜单项或者列表项都支持模板,那么使用菜单时只需要设置菜单项的模板即可改变菜单的样式,同时我们也会发现更多需要实现的功能:
l 同一个菜单的不同菜单项的模板也可能不一样
l 菜单本身如果有模板,那么菜单项需要指定容器
属性和接口
经过上面的分析,我们需要提供以下属性:
- tpl : 控件的模板,是html模板,可以跟配置项进行合并。
- tplRender : 控件模板的渲染函数,当控件的模板根据配置项的值而生成的时候,使用渲染函数。
- childContainer : 控件子控件的容器,控件渲染完DOM后,在渲染子控件时使用。
所使用的接口:
1. setContentTpl (): 设置模板
上面的设计非常简单,但是我们会发现在使用的过程中非常难以使用,在菜单实现中,我们总不能在每个菜单项中都配置模板或者渲染函数,所以必须提供一种方便使用的机制,允许在父控件上设置子控件的模板,这个在后面的扩展里面讲解。
我们来看一个示例:
var menu = new Menu.Menu({ render : '#m1', width : 200, elCls: 'demo-menu', children : [ {href :'http://www.taobao.com',text : '链接1'}, {id : 'm12', href :'http://www.taobao.com', text : '链接2'}, {href :'http://www.taobao.com', text : '链接3'} ], itemTpl:'<span><label>▶ </label><a href="{href}">{text}</a></span>' //菜单项的模板 }); menu.render();
其他模板
在控件状态发生改变时,控件的html或者CSS需要发生改变,例如:
l 菜单选中一项时,菜单项需要添加选中的css
l 表单里面一个表单项验证失败时需要显示错误信息
所以我们需要区别那些状态改变是仅仅改变CSS还是需要增删DOM,把需要增删DOM的内容设置成控件的属性模板,在配置控件时传入,下面是一个文本框控件
var textField = new TextField({ render : '#row', label : '测试字段', elCls : 'control-group span8', controlContainer : '.controls', errorTpl : '<span class="valid-text"><span class="estate error"><span class="x-icon x-icon-mini x-icon-error">!</span><em>{error}</em></span></span>',//错误模板 rules : { required : true, min : 5, max : 10 }, tpl : tpl }); textField.render();
实现
总之,所有可变的的地方都应该使用模板,同时注意易用性和易理解性。