内容


掌握 Dojo 工具包,第 6 部分

Dojo Widget 的高级应用

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 掌握 Dojo 工具包,第 6 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:掌握 Dojo 工具包,第 6 部分

敬请期待该系列的后续内容。

Dojo Widget 是 Dojo 极为重要的部分,因此在对 Dojo Widget 有了全面的了解以后,还应该加强对其使用机制的掌握。

创建 Dijit 的两种方式

Dojo 提供了两种方式给系统开发者去使用其所提供的 Dijit(Dijit 是 Dojo Widget 的简称)。第一种方法是通过直接在页面中静态的写入带有 Dijit 属性的标签去实现该 Dijit 的使用;第二种方法是通过 Javascript 语句,动态的在当前使用页面中生成 Dijit。

第一种方法被称为静态创建 Dijit,而第二种方法则被称为动态创建 Dijit。

静态创建 Dijit

静态创建 Dijit 是通过 HTML 标签属性的方式将 Dijit 引入页面的。因此静态创建 Dijit 的方法简单方便,对于初学使用者也无任何认知困难。在页面需要使用 Dijit 的时候,静态创建 Diijt 往往成为其首选。

静态创建 Dijit 分为三个步骤来完成。

第一步,确定要使用 Dijit 的对象名全称。例如,如果想使用 Dijit 按钮,其对象名全称为 dijit.form.Button。

第二步,在页面的“<head>”和“</head>”标签之间引入即将使用的 Dijit 模块。例如,如果想使用 Dijit 按钮,则需在该页面的 head 部分引入 Dijit 按钮模块。

清单 1.静态创建 Dijit 示例
 <script type="text/javascript"> 
 dojo.require("dojo.parser"); 
 dojo.require("dijit.form.Button"); 
 </script>

dojo.require(“dijit.form.Button”) 表示在页面中引入 Dijit 按钮模块。dojo.require(“dojo.parser”) 表示在页面中引入解析 Dijit 标签属性的功能模块。

静态创建 Dijit 所使用的 Dijit 标签属性不是标准的 HTML,浏览器不能直接对其进行解析。因此需要 dojo.parser 在页面加载完成以后,对整个页面的所有 Dijit 标签属性进行解析,将其转换为浏览器可以识别的标记。

第三步,在页面中需要使用 Dijit 的位置,写入 Dijit 标签属性。例如,如果使用 Dijit 按钮,则为 <div dojotype=“dijit.form.Button”>OK</div>。

动态创建 Dijit

静态创建 Dijit 简单易用,但灵活性差,无法满足实际情况下多变的要求。因此在大多数情况下,更多的是需要动态创建 Dijit。

例如,需要根据用户的选择,动态的创建一定数目一定类型的 Dijit;或者是在页面生成后根据后台运算结果动态的创建 Dijit。

动态创建 Dijit 也分为三个步骤来完成。

第一步,明确要动态创建 Dijit 的对象名全称。

第二步,引入即将使用的 Dijit 模块。例如,如果想使用 Dijit 按钮,则需在该页面的 head 部分引入 Dijit 按钮模块。

清单 2.动态创建 Dijit 示例 1
 <script type="text/javascript"> 
 dojo.require("dijit.form.Button"); 
 </script>

需要注意的是,清单 2 中没有引入 dojo.require(“dojo.parser”)。因为动态创建 Dijit 的过程中会自动完成向 HTML 的转换。

第三步,通过 Javascript 调用对应 Dijit 的动态构造语句,动态创建 Dijit。

清单 3.动态创建 Dijit 示例 2
 function init() 
 { 
 var mydiv = document.createElement("div"); 
 dojo.body().appendChild(mydiv); 
 var mybutton = new dijit.form.Button({label:"OK"},mydiv); 
 }

对于绝大部分的 Dijit,第三步动态创建 Dijit 又必须分为两个步骤。

第一个步骤 :动态创建一个“替代层”,并将该层插入到当前页面 DOM 结构中 Dijit 应处的位置。

第二个步骤 :调用该 Dijit 对应的动态构造语句,例如 new dijit.form.Button(params, srcNodeRef) 去创建该 Dijit。其中“params”是 Dijit 构造时相关的属性参数,“srcNodeRef”是上一步骤中创建的“替代层”。

从 Dojo0.9 开始,Dojo 组织认为创建 Dijit 和确定 Dijit 在页面中的位置(这里的“位置”是指页面 DOM 结构中的相对位置)是两个不同类型的操作。从代码结构优化和软件工程化的角度考虑,这两个不同类型的操作在实际的应用中也应该是相对独立的。因此,在实际创建 Dijit 的时候,首先要动态创建一个“替代层”去将 Dijit 的位置“标注”出来。

在上面的代码中,这个动态创建的“替代层”(mydiv)被插入成为“body”标签的子结点。

var mybutton = new dijit.form.Button({label:"OK"},mydiv)) 表示调用 Dijit 的动态构造语句,并使用 mydiv 作为“替代层”,将动态创建的 Dijit 插入到页面 DOM 结构的相应位置。

但也并不是所有的 Dijit 都必须创建“替换层”。一些 Dijit,其在页面中的位置对其功能没有任何影响。例如 dijit.Tooltip,dijit.TooltipDialog 和 dijit.Dialog 等。因为这类型 Dijit 的显示位置与其在 DOM 结构中的相对位置没有必然的关系,因此在一般情况下,Dojo 会默认的把这些 Dijit 插入到页面 DOM 结构最后面的位置。

此外需要注意的是,如果在动态创建的 Dijit 中再创建子 Dijit,往往会在页面运行时出现一些莫名其妙的情况。Dojo 组织建议在动态创建 Dijit 结束以后,调用 startup()。例如对于上面动态创建的 Dijit 按钮,可在最后加上 mybutton.startup()。加上这段代码的原因与 Dijit 创建完成以后的解析相关。

使用静态创建的模式动态创建 Dijit

静态创建 Dijit 简单易用,动态创建 Dijit 灵活多变。将两种方法的优点结合起来,使用静态模式动态创建 Dijit,在某些情况下将会是一种最优的选择。

首先回顾一下,静态创建 Dijit 的一个完整的过程。当页面加载完成以后,在引入了 Dojo 解析模块的基础上,Dojo 会自动将页面中所有的 Dijit 标签属性解析为标准的 HTML(动态创建的 Dijit,会在创建的过程中自动完成转换)。

因此如果能将 Dijit 标签属性通过动态的方法直接写入页面中,并手动模仿 Dojo 解析 Dijit 标签属性的过程,就会实现以静态创建的模式动态创建 Dijit。

假设当前页面中有一个命名为 mydiv 的层实体,现在通过 Javascript 脚本动态的在这个层实体中写入 <div dojotype=“dijit.form.Button”>OK</div>, 例如 mydiv.innerHTML = <div dojotype=“dijit.form.Button”></div>。那么通过这样的操作,Dijit 按钮就插入到了页面中。

现在面临的问题就是将 mydiv 层实体中的 Dijit 标签解析为 HTML。静态创建 Dijit 的时候,页面加载完成以后会调用相应的 Dojo 解析模块将整个页面的 Dijit 标签属性解析为 HTML。如果能够任意调用 Dojo 的解析模块,则上面通过静态方法在一个层实体中写入的 Dijit 就能被解析为 HTML。通过调用 dojo.parser.parse(), 能够实现对 Dojo 解析模块的调用。dojo.parser.parse() 中填入的参数为需要进行解析的实体。

清单 4.静态模式动态创建 Dijit 示例
 <html> 
 <head> 
 <title>Dijit CSS</title> 
 <script type="text/javascript" src="dojo_path/dojo/dojo.js" 
 djConfig="isDebug: true, parseOnLoad: true"></script> 
 <style type="text/css"> 
	 @import "dojo_path/dijit/themes/tundra/tundra.css"; 
	 @import "js/dojo-release-1.1.0/dojo-release-1.1.0/dojo/resources/dojo.css"
 </style> 
 <script type="text/javascript"> 
	 dojo.require("dijit.form.Button"); 
	 dojo.require("dojo.parser"); 
	 function init() 
 { 
	 var mydiv = document.createElement("div"); 
	 mydiv.id = "mydivid"; 
	 dojo.byId("mybody").appendChild(mydiv); 
	 mydiv.innerHTML = '<div dojotype="dijit.form.Button">OK</div>'; 
	 dojo.parser.parse(mydiv); 
 } 
 dojo.addOnLoad(init); 
 </script> 
 </head> 
 <body class="tundra" id="mybody"> 
 </body> 
 </html>

最后将动态创建 Dijit 的方法和静态创建 Dijit 的方法进行一个全面的比较。

抛开动态创建和静态创建的表象从本质上说,创建一个 Dijit 对于动态和静态都需要以下相同的几项要素。

  • Dijit 将插入 DOM 结构中的位置。静态创建 Dijit 是通过直接写入到页面中,表明其所在 DOM 结构中的位置;而动态创建 Dijit 则需要通过一个“替代层”来实现 Dijit 插入到 DOM 树中的合适位置。
  • 表明要创建的 Dijit 类型。静态创建 Dijit 是通过使用 dojotype 标签属性来表明;而动态创建 Dijit 则是通过调用该 dijit 相应的动态构造语句来表明。
  • 在创建一个 Dijit 时,需设置其的相关属性。静态创建 Dijit 是通过标签属性来定义的;而动态创建 Dijit 则是通过在该 Dijit 相应构造语句中直接设定属性实现的。
表 1.两种方法的比较
比较项 静态创建 Dijit 动态创建 Dijit
Dijit 位置 直接在相应的位置写入 Dijit 通过替代层定位
Dijit 类型 通过标签属性 DojoType 确定 通过调用相应 Dijit 的动态构造语句
设置属性 通过标签属性来定义 Dijit 属性 直接在动态构造语句中设定

Dijit 的操控

能通过静态或动态两种方式创建 Dijit 仍然不能够达到在页面中对 Dijit“为所欲为”的要求。目前的情况是,在创建一个 Dijit 之前,可以尽可能的对 Dijit 进行各种预定义的操作,一旦 Dijit 被创建以后,就很难再对 Dijit 施加影响。

Dojo 针对页面中已存在 Dijit 的操控给出了以对象操作为基础的解决方法。

要对 Dijit 进行操控,首先是要获得这个 Dijit 实体。正如要将一块玉石打磨成美玉,首先是要获得那块玉石。在 Dojo 下,有两种方式能获得 Dijit 实体。

第一种,动态创建一个 Dijit 的时候,Dijit 动态构造语句的返回值就为该 Dijit 实体。将这个 Dijit 动态构造语句的返回值赋值给一个变量,则可以通过这个变量实现对新创建 Dijit 实体的操控。例如 var mybutton = new dijit.form.Button({label:"OK",id:”testid”}, dojo.byId("mydivid")) 新创建了一个 Dijit 按钮实体,其动态构造语句的返回值赋给了变量 mybutton,因此可以通过 mybutton 来操控新创建的这个 Dijit 按钮实体。

如果想将新创建的 Dijit 按钮实体的 name 属性,由空字符串修改为“good”,则可以通过操控 mybutton 来实现。例如 mybutton.name = “good”通过操控 mybutton 的 name 属性,实现了对新创建 Dijit 按钮实体属性的修改。

第二种,在知道某个 Dijit 实体 id 的情况下,则可以通过 dijit.byId() 获得这个 Dijit 实体;或者是在 Dijit 中声明一个属性 jsId,则可以直接通过 jsId 的值来操控这个 Dijit 实体。

例如 var mybutton = new dijit.form.Button({label:"OK",id:”testid”}, dojo.byId("mydivid")) 构建了一个 Dijit 实体。则由其动态构造语句,可以知道该 Dijit 按钮实体的 id 为“testid”。

而后通过 var yourbutton = dijit.byId(“testid”) 就可以获得这个 Dijit 按钮的实体。

需要注意的是,通过 id 来获得 Dijit 实体没有通过 dojo.byId() 方法而是使用的 dijit.byId() 方法。在 Dojo 体系中,如果想通过 Dijit 的 id 来获得 Dijit 实体,只能通过 dijit.byId()。而作用与 document.getElementById() 相同的 dojo.byId(),无法获得任何 Dijit 实体。

Dojo 组织认为 DOM 对象实体和 Dijit 实体是两个完全不同的对象实体类型。通过 id 去获得这两种实体也应该使用不同的方法。dojo.byId() 被分配用来获得 DOM 对象实体,而 dijit.byId() 则被分配用来获得 Dijit 类型的实体。

从实际情况来看,这种区分也是非常必要的。假如获得 DOM 对象实体和获得 Dijit 实体都使用 dojo.byId(), 且该 Dijit 实体中定义了 width 属性(注意这个 width 属性与该 Dijit 的宽度没有任何关系,这个 width 属性可能是该 Dijit 中某个小图片的宽度),那么当尝试修改 width 属性的时候,浏览器将无法明白希望修改的是该 Dijit DOM 对象属性的 width(即该 Dijit 在页面中的宽度)还是希望修改该 Dijit 实体的 width 属性(即可能该 Dijit 中某个小图片的宽度)。

Dijit 可以通过 dijit.byId() 方法获得该 Dijit 实体。但在某些情况下,也需要获得该 Dijit 的 DOM 对象实体。所有的 Dijit 实体都有一个属性 domNode,通过该属性可以得到该 Dijit 的 DOM 对象实体。

因此某个 Dijit 小图片的 width 属性将为 dijit.byId().width; 而该 Dijit 在某个页面中的宽度为 dijit.byId().domNode.width。(注意 dojo.byId() 既不能获得 Dijit 实体,也不能获得 Dijit 的 DOM 对象实体)

如果具有 OO 编程的经验,则必然知道对于一个完整定义的对象,其必有自己的属性和方法。对于 Dijit,作为一种 Dojo 体系下定义的对象,其必然也有自己的属性和方法。而这些属性和方法就是操控 Dijit 的“钥匙”。

但是就其现在来说,完全记住掌握每个 Dijit 的方法和属性是一个“不可能的任务”,而且随着 Dojo 的发展,其 Dijit 的种类会越来越庞大。因此作为 Dojo 的使用者必须掌握快速查询 Dijit 方法和属性的技能。

Dojo 的使用者需要的是一个能方便快捷查询 Dijit 属性和方法的手册。Dojo 组织没有给出一个专门的 Dijit 属性和方法手册。但是仍然可以通过以下两种方法间接得到 Dojo 使用者所期望的信息。

第一种方法,通过使用 Dojo 组织在线 API(http://api.dojotoolkit.org/)。

第二种方法,是利用 Firefox 调试工具 Firebug 的帮助来查看 Dijit 实体的方法和属性。当获得 Dijit 实体的时候,通过 Firebug 支持的 console.debug() 将已经获得的 Dijit 实体输出。接着再点击 Firebug 的 Console 窗口中输出的 Dijit 实体,将可在 Firebug 的 DOM 窗口中观察到该 Dijit 实体所有的方法和属性。

在实际的工程开发中,建议使用这种利用 Firefox 调试工具 Firebug 的帮助来查看 Dijit 的方法。

清单 5.查看 Dijit
 <script type="text/javascript"> 
 dojo.require("dijit.form.Button"); 
 function init() 
 { 
 var mydiv = document.createElement("div"); 
 mydiv.id = "mydivid"; 
 dojo.body().appendChild(mydiv); 
 var mybutton = new dijit.form.Button({label:"OK"}, dojo.byId("mydivid")); 
 console.debug(mybutton); 
 } 
 dojo.addOnLoad(init); 
 </script>

在清单 5 中,动态创建了一个 Dijit 实体,并使用 console.debug() 将其在 Firebug 的 Console 窗口中输出。

图 1.Console 中的 Dijit
图 1 Console 中的 Dijit
图 1 Console 中的 Dijit

图 1 显示的是在 Console 窗口中输出的 Dijit 实体。

当点击 Firefox 的 Console 窗口中输出的 Dijit 实体时,Firebug 的 DOM 窗口会列出该 Dijit 实体的所有属性和方法。

图 2.DOM 窗口中的 Dijit 属性和方法
图 2 DOM 窗口中的 Dijit 属性和方法
图 2 DOM 窗口中的 Dijit 属性和方法

图 2 显示的是在 DOM 窗口中列出的 Dijit 实体的所有属性和方法。

与 Dojo 组织在线 API 中的 Dijit 属性和方法列表进行对比,会发现在 Firebug 的 DOM 窗口中列出的属性和方法比在线 API 上 Dijit 的属性和方法要多得多。同时多出的属性和方法基本上都是以“_”开头的。

事实上,这些以“_”开头的属性和方法是 Dojo 组织希望隐藏起来的 Dijit 的属性和方法。从其表现出来的功能角度,可以将这些属性和方法理解为 Dijit 实体的私有属性和私有方法。但由于 Javascript 不具备面向对象的所有特性,因此 Dijit 的这些属性和方法也就不能像面向对象中的私有属性和方法一样被禁止访问。

虽然这些属性和方法在 Firebug 中的 DOM 窗口中被列了出来。但建议在一般情况下,尽量不要使用这些 Dijit 希望被隐藏的属性和方法。

清单 6.Dijit 按钮操控实例
 <html> 
 <head> 
 <title>Dijit CSS</title> 
 <script type="text/javascript" src="dojo_path/dojo/dojo.js" 
 djConfig="isDebug: true, parseOnLoad: true"></script> 
 <style type="text/css"> 
	 @import "dojo_path/dijit/themes/tundra/tundra.css"; 
	 @import "dojo_path/dojo/resources/dojo.css"
 </style> 
 <script type="text/javascript"> 
	 dojo.require("dijit.form.Button"); 
	 var mybutton; 
	 function init() 
	 { 
	 var mydiv = document.createElement("div"); 
	 dojo.body().appendChild(mydiv); 
	 mybutton = new dijit.form.Button({label:"OK"}, mydiv); 
	 console.debug(mybutton); 
	 setTimeout("firstchange()",3000); // 延迟 3 秒执行 firstchange() 函数
	 } 
	 function firstchange() 
	 { 
	 alert("This Dijit Button Label is "+mybutton.label); 
	 setTimeout("secondchange()",3000); 
	 } 
	 function secondchange() 
	 { 
	 mybutton.setLabel("Good Guy"); 
	 setTimeout("mydestory()",3000); 
	 } 
	 function mydestory() 
	 { 
	 mybutton.destroy(); 
	 } 
	 dojo.addOnLoad(init); 
 </script> 
 </head> 
 <body class="tundra"></body> 
 </html>

在清单 6 中,动态创建了一个 Dijit 按钮实体。在创建 Dijit 按钮实体 3 秒后,弹出一个提示窗口输出 Dijit 按钮实体属性 label 的值。再经过 3 秒后,调用 Dijit 按钮实体的 setLabel() 方法修改其属性 label 的值。再经过 3 秒,最后调用 Dijit 按钮实体的销毁方法 destory() 方法,在当前页面中删除动态创建的 Dijit 按钮实体。

label 属性值的修改不能直接通过给 Dijit 按钮实体 label 属性赋值的方法来完成,必须通过调用 setLabel() 方法才能成功修改其值。这样就避免了开发人员在无意中修改 Dijit 实体属性的值,增加了代码的安全性和健壮性。

不仅仅 Dijit 按钮实体具有 destory() 方法,所有的 Dijit 实体都可以依靠其自己的 destory() 方法,将自己在当前页面中的“生命结束”。

Dijit 的样式

Dojo 提供了大量的 Dijit 让开发者选择使用。当这些功能各异的 Dijit 组合在一起以后,并没有显得纷杂和混乱,反而给人以整齐,清爽的感觉。控制着这些数量众多的 Dijit 以同一种样式进行展现的就是 Dijit 的样式主题。

认识 Dijit 的样式主题

Dojo 目前给出的统一样式主题有四个,包括 Tundra,Soria,Nihilo,A11y。其中 A11y 是特别为残障人士使用浏览器时设计的样式主题(本节所讨论的样式主题以 Dojo1.1.0 版本为准)。

在 dojo_path/dijit/themes 文件夹下有一个 Dijit 的样式主题测试页面 themeTester.html。用浏览器运行该页面,首先将看到默认的以 Tundra 为样式主题的几乎所有的 Dijit。

在 themeTester.html 页面的右下脚,有一个“Alternate Themes”的按钮选项,点击这个按钮后,可以依据给出的选项,将页面中的所有 Dijit 转换为 Soria 主题样式或者是 Nihilo 主题样式。

要让页面中的所有 Dijit 使用同一种样式主题来展现,需要通过两步来完成。

第一步,在页面的 head 部分引入期望使用的样式主题的 CSS 文件。例如,如果使用 Soria 样式主题。

清单 7.在 head 中引入 CSS
 <style type="text/css"> 
 @import "dojo_path/dijit/themes/soria/soria.css"; 
 @import "dojo_path/dojo/resources/dojo.css"; 
 </style>

清单 7 中的代码显示了如何引入 Soria 样式主题的 CSS 文件。

第二步,在页面 body 标签中定义属性 class 为所期望使用的样式主题名。如果使用 Soria 样式主题。

清单 8.使用 CSS
 <body class="soria">

清单 8 显示了如何在页面中使用 Soria 样式主题。

除了让页面中的所有 Dijit 使用同一种样式主题以外,也可以通过给特定的 Dijit 指定 class 属性来实现特定的 Dijit 使用特定的样式主题。

清单 9.在 Dijit 中指定样式
 <html> 
 <head> 
 <title>Dijit CSS</title> 
 <script type="text/javascript" src="dojo_path/dojo/dojo.js" 
 djConfig="isDebug: true, parseOnLoad: true"></script> 
 <style type="text/css"> 
	 @import "dojo_path/dijit/themes/tundra/tundra.css"; 
	 @import "dojo_path/dijit/themes/soria/soria.css"; 
	 @import "dojo_path/dojo/resources/dojo.css"; 
 </style> 
 <script type="text/javascript"> 
	 dojo.require("dijit.form.Button"); 
	 dojo.require("dojo.parser"); 
 </script> 
 </head> 
 <body class="tundra"> 
 <div dojotype="dijit.form.Button">OK</div> 
 <div dojotype="dijit.form.Button">BAD</div> 
 <div dojotype="dijit.form.Button" class="soria">OK</div> 
 <! — - 该 Dijit 按钮使用 Soria 样式主题  
 </body> 
 </html>

在清单 9 中使用 Tundra 作为页面的全局样式主题。但在声明最后一个 Dijit 按钮实体的时候,通过指定 class 属性为 soria,使得该 Dijit 按钮实体使用 Soria 作为其样式主题。

需要注意的是在引入样式主题 CSS 文件的时候,需要将 Tundra 的 CSS 文件和 Soria 的 CSS 文件都在页面的 head 部分引入。

修改 Dijit 的样式

在着手掌握修改 Dijit 样式主题的方法之前,非常有必要首先了解一下 Dijit 样式主题的设计框架。

Dijit 的设计理念遵循逻辑层和表现层相分离的基本原则。其中的表现层又进一步分为“骨架”和“血肉”。“骨架”是指通过 HTML 构建起整个 Dijit 的 DOM 结构,这些 HTML 像人体的骨架一样构造出了 Dijit 的基本外貌;而“血肉”则是指在基于“骨架”的基础上,通过 CSS 定义细致的刻画出 Dijit 的最终“形象”,这些 CSS 定义像人体的血肉一样让一个一个的 Dijit“鲜活”了起来。而要修改 Dijit 的样式主题,就是要修改那些让 Dijit“鲜活”起来的 CSS 定义(Dijit“骨架”的修改只能靠修改 Dojo 包中 Dijit 定义的源码来完成)。

Dijit CSS 定义的层次结构非常复杂。打开 Dojo 包可以发现在 dojo_path/dojo 文件夹下有 dojo.css 文件,在 dojo_path/dijit 文件夹下有 dijit.css 文件,在 dojo_path/dijit/themes 文件夹下又有每个 Dijit 基于不同样式主题的 CSS 文件。

事实上,就其开发者的工作来说,完全没有必要花费大量的时间去弄清楚 Dijit CSS 定义的“支支叶叶”,只需要了解 Dijit CSS 定义的大体层次结构就完全能满足实际工作中的需要。

Dijit 的 CSS 定义大体上分为三个层次。第一个层次是 Dijit 总体样式的定义,主要是通过 dijit.css 来完成的;第二个层次是各个样式主题的定义,主要是分别通过 tundra.css、soria.css 和 nihilo.css 三个 CSS 文件分别完成的。第三个层次是各个 Dijit 具体展现形式的定义,主要是通过各个 Dijit 的同名 CSS 文件来完成的(dojo.css 定义的内容与 Dijit 样式不具有直接的关系,因此不纳入 Dijit CSS 定义的体系中)。

然而如果以 Dijit 的三层 CSS 定义体系为依据来查询相关 Dijit 的 css 定义,进而达到修改相应 Dijit 样式主题的目的,这无疑将是一种愚公移山的行为。

事实上 Firebug 给出了一个非常好的功能。其能帮助开发者快速找到页面中每个 Dijit 样式的全部 CSS 定义,并对应 Dijit CSS 定义的层次结构进行显示。

图 3.Firebug 中的 Dijit 样式
图 3 Firebug 中的 Dijit 样式
图 3 Firebug 中的 Dijit 样式

在图 3 中通过 Firebug 查看了 Dijit 按钮的 DOM 结构和 CSS 定义。其中 CSS 定义显示在 Firebug 的 style 窗口中。在 Firebug 的 style 窗口中分别以 Dijit 层次、Tundra 层次和 Dijit 按钮层次三个不同的等级,将 Dijit “OK”按钮中使用到的 CSS 定义进行了显示(在选择 Dijit “OK”按钮的时候,可以使用“Inspect”模式,先选中页面上的 Dijit “OK”按钮,然后按回车,则可让 Firebug 的 style 窗口恰好显示 Dijit “OK”按钮的 CSS 定义)。

从 Firebug 的 style 窗口中观察 Dijit 按钮的 CSS 定义,会发现有些 CSS 定义项是被横线划掉了的。这表示当前的这些被横线划掉的 CSS 定义被后面的 CSS 定义给重写了,这些被划掉的 CSS 定义在当前 Dijit 按钮上是无效的。

要修改某个 Dijit 实体的 CSS 定义,可以依据 style 窗口中的 CSS 定义,在页面的 head 部分重新定义相应 CSS 定义的 class。

在图 3 中,查看 Dijit 按钮的 CSS 定义可以发现,Dijit 按钮的 border 宽度是在 .tundra、.dijitButtonNode 中定义的。要修改 Dijit 按钮的 border 宽度,需要重新定义 .tundra、.dijitButtonNode 中的 border-width 属性。

清单 10.CSS 定义
 .tundra .dijitButtonNode 
 { 
 border-width:10px; 
 }

清单 10 的 CSS 定义将 Dijit 按钮的 border 宽度属性修改为 10px,而其它属性的值没有变化。

图 4.在 firebug 中查看样式
图 4 在 firebug 中查看样式
图 4 在 firebug 中查看样式

图 4 是将 Dijit 按钮的 border-width 加粗到 10px 后的效果。可以发现 style 窗口中原来的 .tundra、.dijitButtonNode 中定义的 border-width 属性项被横线划掉了。这是因为在当前页面中重新对其进行了定义,可以在其上的定义项中看见新定义的 border-width 值为 10px。

自定义 Dijit 的样式主题

在一些情况下,仅仅是通过修改 Dijit 已有的样式主题可能不能满足实际的需求,而是希望 Dijit 能直接使用完全自定义的样式主题。

如果要让当前页面中 Dijit 直接得到自定义的样式主题,最直观的想法是让所有的 Dijit 能直接使用自定义的 CSS,而不是通过修改每个 Dijit 已经存在的 CSS 定义来实现。修改 Dijit 的样式主题必须针对每一个 Dijit 单独操作,但是通过自定义的样式主题就可以实现对 Dijit 样式主题的批量操作。这是修改 Dijit 的样式主题和自定义 Dijit 的样式主题最本质的区别。

自定义 Dijit 样式的主题有三种方法。需要注意的是,在通常情况下,只建议使用前两种方法。

第一种方法是直接定义相关样式主题属性。

<div style= "margin: 30px;" dojotype="dijit.form.Button">OK</div> 直接定义了 Dijit 按钮 style 属性的 margin 值为 30px。其效果是该 Dijit 按钮样式主题的 margin 值变为 30px。

结合上一节修改 Dijit 样式主题的例子,考虑使用同样的方法将 border-width 值变为 10px。

在实际运行效果中会发现页面中的 Dijit 按钮没有任何改变。其原因是在于当前直接定义样式主题属性中的 border-width 所能影响到的层和修改 Dijit 样式主题中 border-width 所影响到的层是不同的层。通过 Firebug 的 HTML 窗口可以发现其区别。在直接定义样式主题属性中的 border-width 所能影响到的层中,没有定义 border-style 等属性值,所以 border-width 无法起到作用。

图 5.Firebug 中查看样式
图 5 Firebug 中查看样式
图 5 Firebug 中查看样式

在知道原先修改失效原因的情况下,可以将代码进行修改,以期得到希望的效果。

清单 11.直接定义相关样式主题
 <div style= " border-width:10px; border-style:solid;" dojotype="dijit.form.Button"> 
 OK 
 </div>

清单 11 的代码可以展现出期望的结果。

第二种方法通过定义与 id 相关联的 CSS 属性。

清单 12.定义与 id 相关联的 CSS
 <style> 
 #testme { margin: 30px; } 
 </style> 
 <div id="testme" dojotype="dijit.form.Button">OK</div>

在清单 12 中定义了 id 为 testme 的实体,其 style 属性的 margin 值为 30px。

第三种方法通过定义与 class 相关联的 CSS 属性。

清单 13.定义与 class 相关联的 CSS
 <style> 
 .testme { margin: 30px; } 
 </style> 
 <div class="testme" dojotype="dijit.form.Button">OK</div>

在清单 13 中自定义 Dijit 样式主题的方法并不推荐使用,因为在实际情况中,使用该种方法往往会出现运行结果与预计不符合的情况。其原因是当一个实体使用 CSS 的 class 来进行效果修饰的时候,如果出现多个 class 中定义的属性值冲突的情况,则将会以最后面的一个属性值为基准来执行。那些被自动屏蔽掉的 CSS 定义就如 Firebug 的 style 窗口中被横线划掉的 CSS 定义一样。

结束语

本文关注的是 Dijit 的高级使用。其目的并不是为了让你的应用程序更加绚丽多彩,而是帮助你更理性的去看待 Dijit 的强大,更成熟的去使用 Dijit 进行开发,以及更沉着的去解决 Dijit 使用中出现的问题。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=442449
ArticleTitle=掌握 Dojo 工具包,第 6 部分: Dojo Widget 的高级应用
publish-date=11022009