Widget的实例属性
Widget有两个重要属性BOUNDING_TEMPLATE 和 CONTENT_TEMPLATE。初始值都是”<div></div>”,这为多数widget提供一个标准html结构,包含双层嵌套的div。但并不是所有的widget都适用,比如按钮使用<span> <a></a></span> 而不是<div><div></div></div>结构,其实Widget不强制要求使用一个大容器(contentBox),这两个属性可以使用任意html标签,比如我用a来描述按钮 BOUNDING_TEMPLATE: ‘<a>’, CONTENT_TEMPLATE: null,</a>
在你不需要contentBox的时候就将其设置为null,这时contentBox的配置会继承自boundingBox。不要将widget的所有HTML都放在这两个属性中,这两个属性中的元素要尽量简单,在renderUI中使用代码创建其余的html标签。Widget会给所有你指定的标签加上id和class,形式诸如yui3-xxxx, yui3-xxxx-visible 或 yui3-xxxx-disabled,其中xxxx是小写的NAME属性。
Widget实例方法
Widget的初始化有多个步骤,除了会在对象实例化时调用initializer(构造函数)外,在销毁时也会调用destructor函数(析构函数),这两个方法都继承自Base。Widget又增加了renderUI, bindUI, syncUI三个函数,在widget的render方法被调用时,这三个函数会依次执行。
renderUI负责生成widget最基本的HTML骨架,包括boundingBox和contentBox,如果考虑到渐进增强, renderUI会先检查元素是否已存在于DOM中,这是因为如果设置HTML_PARSER属性,配置属性中定义的元素会被事先生成好。如果元素没有事先生成,我们才需要通过renderUI来创建。
最简单的生成HTML的方法(假设没有使用渐进增强)就是使用Y.Node.create方法: renderUI: function () { var cbx = this.get(CBX); cbx.append(Y.Node.create(Y.substitute(Y.Xxxx.TEMPLATE, CLASS_NAMES))); },
这段代码的运行需要特定的上下文,首先,要声明常量CBX(见本篇文章第一个代码块),其次,widget所需的模块都加载完全,加载widget之前会自动加载其依赖的Node, Y.substitute是可选模块,如果需要则要把’substitute’ 加入到requires中。此外还要有一个作为widget内容模板的名为TEMPLATE的静态变量,你可以和其它静态成员一起定义(通过ATTRS定义)它。最后常量CLASS_NAMES应当也已经事先定义好了。
我通常在模块开头,和BBX,CBX一起定义CLASS_NAMES(见本文第一个代码块): var BBX = ‘boundingBox’, CBX = ‘contentBox’, NAME = ‘button’, // other constants and shortcuts …. YCM = Y.ClassNameManager.getClassName, getClassName = function () { var args = Y.Array(arguments); args.unshift(NAME); return YCM.apply(this, args).toLowerCase(); }, LABEL = ‘label’, PRESSED = ‘pressed’, ICON = ‘icon’, CLASS_NAMES = { pressed: getClassName(PRESSED), icon: getClassName(ICON), label: getClassName(LABEL), noLabel: getClassName(‘no’, LABEL) };
CLASS_NAME为一个object常量,其中的属性值由ClassNameManager(包含在Widget中)生成。在以上代码中,我先声明一个指向Y.ClassNameManager.getClassName的缩写YCM,然后声明一个只能在模块内部访问的私有函数getClassName,这个函数的功能与Widget中的同名函数getClassName的功能很类似,只是widget中的getClassName是个静态函数,可以用来生成静态变量。CLASS_NAMES中表示样式名的属性值就是用它生成的。现在,我就可以这样定义TEMPLATE中的样式名了: TEMPLATE: ‘<label>’,</label>
这还不够,我还想将其它的值比如配置属性中的值加入模板中。可以这样做: this.get(CBX).append(Y.Node.create(Y.substitute(TEMPLATE , CLASS_NAMES, Y.bind(function (key, suggested, arg) { return (key === ‘_’?this.get(arg):suggested); },this))));
我给Y.substitute增加了第三个参数,一个函数。通常,Y.substitute中的占位符是由一对花括号包围的字符串,如果其中有空格,占位符就会被一分为二。空格前面的部分为key,空格后的部分为可选参数。当Y.substitute的第三个参数是一个函数时,这个特性十分有用。比如在此例中,第一个参数是key,第二个参数是用于替换的内容,此例中是CLASS_NAME,第三个是可选参数。所以在上面的语句之后,我可以这样使用模板: TEMPLATE: ‘<label for="”{_" />’,
Y.substitute在执行时先碰到{label},开始在CLASS_NAME中搜索,并找到对应值‘yui3-button-label’。然后以‘label’, ‘yui3-button-label’ 和 undefined为参数调用替换函数。因为key不等于’_’,所以函数返回第二个参数中值,即原始的样式名。当遇到{_ id}时,因为在CLASS_NAMES中没有’_’属性,所以会以传入参数‘_’, undefined 和 ‘id’调用替换函数,函数会从配置属性中读取’id’的值。在遇到占位符{_ value}时函数将执行同样的操作。
出处:Taobao.com UED Team
责任编辑:bluehearts
上一页 使用YUI 3开发Web应用的诀窍 [4] 下一页 使用YUI 3开发Web应用的诀窍 [6]
◎进入论坛网页制作、WEB标准化版块参加讨论,我还想发表评论。
|