Dojo 1.6 官方教程: 创建自定义Dojo小部件(Widget)
在这个教程中,我们将会演示如何利用Dojo 和Dijit框架来创建自定义的小部件。 主要会使用到dijit._Widget 和dijit._Templated 基类和mixin。
对dijit框架的基础知识,可以参看前两篇教程 难度:中等 适用Dojo版本: 1.6 作者:Brian Arnold Brian Arnold is a software engineer at SitePen,Inc. He has a lovely wife,two cute dogs,is an active member of (and presenter at) Webuquerque,and ranks among the top 3% of fake guitarists in Rock Band. 原文连接:http://dojotoolkit.org/documentation/tutorials/1.6/recipes/custom_widget/ 译者 : feijia tiimfei@gmail.com Dojo的Dijit 库包含了丰富的界面小部件(Widgets),通过使用这些小部件,可以打造出强大的Web应用界面,从高级的表单元素,到复杂页面布局。 但是对于一些较复杂的应用,开发者仍会碰到做进一步定制的需求,例如非常复杂的信息展示需求。你当然可以手动的自己构造DOM来展示数据,但是如果利用Dijit已经提供的框架和工具,我们可以快速的开发出灵活又强大的自定义小部件。 场景假设我们需要开发一个能展示所有Dojo教程作者的简介信息的页面。我们手头的数据源是如下的JSON数据: [ { "name": "Brian Arnold","avatar": "/includes/authors/brian_arnold/avatar.jpg","bio": "Brian Arnold is a software engineer at SitePen,Inc.,..." },/* More authors here... */ ] 我们的需求是把这些信息以下面的DOM结构展示在页面上: <body> <!-- Headers and whatnot --> <h2>Authors</h2> <div id="authorContainer"> <!-- Authors go here! --> </div> </body> 当然,我们希望这个展示页面可以再加点效果,例如当鼠标移到某个作者上时,背景色可以淡入显示。 最终展示的页面效果如下:
解决方案
第一步是为自定义小部件创建必要的目录结构
第二步 创建展示单个作者的HTML片段
<div> <h3>Brian Arnold</h3> <img src="/includes/authors/brian_arnold/avatar.jpg"> <p>Brian Arnold is a software engineer at SitePen,...</p> </div> 第三步 把HTML片段变成Dijit模板
<div> <h3 data-dojo-attach-point="nameNode">${name}</h3> <img class="${baseClass}Avatar" src="" data-dojo-attach-point="avatarNode"> <p data-dojo-attach-point="bioNode">${!bio}</p> </div> 在这一模板中: 1. 我们使用 ${attribute}的语法来直接插入一些值,例如这里我们插入了作者姓名${name} 2. 类似的,还有一种语法是${!attribute}. 这两者的区别是,${!attribute} 会对值原样插入而不做转义。在这里我们在${!bio}位置要替换的值会包含一些HTML标记,我们不希望Dijit._templated 对这些标记做转义。 3. 所有基于dijit._Widget的小部件都有一个baseClass属性。 4. 在上述模板中,我为每个节点都定义了附着点属性,这样在我的代码中就可以直接使用诸如myAuthor.nameNode 这样的代码直接访问到H3节点。 你也许已经注意到了我在模板中的img标签里没有指定src属性值。 那么如果我们的数据里某个作者没有包含头像图片怎么办?我们需要能够在创建我们的小部件时自动设定处理这类情形的默认值。 后面的步骤会进一步解释如何解决这个问题。 第四步 使用dojo.declare创建小部件的类这一步我们要在custom目录里创建AuthorWidget.js 。 并且我们添加一个默认的头像的图片文件。 // custom.AuthorWidget dojo.provide("custom.AuthorWidget"); // 声明依赖的模块和基类 dojo.require("dijit._Widget"); dojo.require("dijit._Templated"); // Create our widget! dojo.declare("custom.AuthorWidget",[dijit._Widget,dijit._Templated],{ /* 我们的自定义小部件属性将会被添加在这里 */ }) // and that's it! 这段代码中: dojo.declare("custom.AuthorWidget",{ // 设置一些默认值 // These typically map to whatever you're handing into the constructor name: "No Name",// Using dojo.moduleUrl,we can get a path to our AuthorWidget's space // and we want to have a default avatar,just in case avatar: dojo.moduleUrl("custom.AuthorWidget","images/defaultAvatar.png"),bio: "",// 加载我们的模板 - important! templateString: dojo.cache("custom.AuthorWidget","templates/AuthorWidget.html"),// 将会被应用到模板根节点的css类名 baseClass: "authorWidget",// 指向我们背景动画对象的引用 mouseAnim: null,// 用于背景的颜色属性 baseBackgroundColor: "#fff",mouseBackgroundColor: "#def" }); 首先我们定义了一些属性用于保存作者的基本信息:姓名,简介和头像。我们也提供了这些属性的默认值。 在设置头像的默认值时,我们使用了dojo.moduleURL来引用当前小部件所在的路径,并访问该路径下的图片文件夹。 通过使用templateString属性,和dojo.cache 我们加载了之前定义的模板文件 设置baseClass属性,该属性会被设置为小部件的DOM根节点的CSS类。 在这里就是我们模板中的最外层div节点。 我们还留出了用于设置动画的属性和背景色的属性。 到目前为止,我们的小部件已经初具雏形,实际上它已经可以运行并显示一些简单的信息了。 当然我们还需要进一步完善它。 接下来我们会添加postCreate方法,一个定制的头像设定方法,已经一个辅助方法用来变换背景颜色。 postCreate方法是用来添加我们的工作逻辑的主要入口。它的调用时机是在小部件的DOM结构成功创建后,但是还没有被添加到页面的DOM树之前(也即用户看不到这个小部件的DOM节点)。因此通常我们把初始化的工作放在这个方法中。 postCreate: function(){ // Get a DOM node reference for the root of our widget var domNode = this.domNode; // Run any parent postCreate processes - can be done at any point this.inherited(arguments); // Set our DOM node's background color to white - // smoothes out the mouseenter/leave event animations dojo.style(domNode,"backgroundColor",this.baseBackgroundColor); // Set up our mouseenter/leave events - using dijit._Widget's connect // means that our callback will execute with `this` set to our widget this.connect(domNode,"onmouseenter",function(e) { this._changeBackground(this.mouseBackgroundColor); }); this.connect(domNode,"onmouseleave",function(e) { this._changeBackground(this.baseBackgroundColor); }); } 在postCreate里我们利用baseBackgroundColor属性设置了domNode的背景色,并且设置了onmouseenter和onmouseleave的事件处理函数,因此当鼠标悬停在我们的DOM节点上时,_changeBackground 函数就会被调用。 下面我们来看看这个函数: _changeBackground: function(toCol) { // If we have an animation,stop it if (this.mouseAnim) { this.mouseAnim.stop(); } // Set up the new animation this.mouseAnim = dojo.animateProperty({ node: this.domNode,properties: { backgroundColor: toCol },onEnd: dojo.hitch(this,function() { // Clean up our mouseAnim property this.mouseAnim = null; }) }).play(); } 注: 为什么我们要在这个方法名前加下划线呢?这是一种dojo的命名规范,在方法和对象属性前加下划线表示该方法或对象是类内部成员,不应被用户直接使用。虽然JavaScript语言没有强制禁止这类调用,但是这是一个良好的编程习惯,也是一种提示用户正确使用API的方法。 在这个方法中,我们先检查是否当前有动画正在执行,如果有的话我们先停止它。 然后在设置新的动画并保存在mouseAnim中,并开始播放。 这个例子十分类似于我们在Dojo动画教程http://dojotoolkit.org/documentation/tutorials/1.6/animation/ 中的效果,只不过颜色有所差别。 最后,我们需要解决一个问题,就是如果某个作者没有提供头像图片,我们需要给他设置一个默认的头像。 这里我们通过创建一个定制的属性设置方法(custom setter) 来实现。 这类方法有固定的命名规则, _setXXXAttr 其中XXX是你要设置的属性的名称(首字母需大写)。 例如我们这里要设置的是“avatar属性,因此我们需要的方法名是_setAvatarAttr 在小部件被创建或者用户使用属性设置方法:myWidget.set("avatar",somePath) 时,定制属性方法就会被调用. _setAvatarAttr: function(av) { // We only want to set it if it's a non-empty string if (av != "") { // Save it on our widget instance - note that // we're using _set,to support anyone using // our widget's Watch functionality,to watch values change this._set("avatar",av); // Using our avatarNode attach point,set its src value this.avatarNode.src = av; } } 这个方法主要是做一个安全检查,在用户传入空字符串时,就使用默认的头像。 从Dojo1.6开始,所有基于dijit._Widget的小部件都会自动继承dojo.Stateful ,这个类加入了对类属性的变化的监控。我们在_setAvatarAttr 中使用this._set() 方法就是为了遵循dojo.Stateful的规则,保证所有属性的变化可以被检测到。 所有这些都完成后,我们现在有了一个可以工作的小部件。 虽然看起来还不是那么美观。 查看示例 第五步: 美化
/* AuthorWidget.css */ .authorWidget { border: 1px solid black; width: 400px; padding: 10px; overflow: hidden; /* I hear this helps clear floats inside */ } .authorWidget h3 { font-size: 1.5em; font-style: italic; text-align: center; margin: 0px; } .authorWidgetAvatar { float: left; margin: 4px 12px 6px 0px; max-width: 75px; max-height: 75px; } 可以看到我们定义了authorWidget 类,这个类是baseClass所制定的,它会被应用到模板的div根节点上。 同时,模板中还有 ${baseClass}Avatar类,因此我们定义了authorWidgetAvatar类。(这只是一些最基本的美化,别对我要求太高了,我不是一个设计师) 小结
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |