Dojo Toolkit与其他JavaScript类库最大的不同是Dojo的UI组件系统:Dijit。这是一个灵活的,综合的Dojo 模块集合(由相对应的例如图片,CSS文件等等补充)。Dijit能够帮助你创建灵活的,可扩展的,现代的组件。想要学习如何安装,配置并且使用基本的Dijit在你的web应用中,请继续阅读。
因为Dijit包括了一系列的UI组件,他绑定了4个支持的主题:nihilo, soria, tundra 和claro。每个主题包括了一系列的图片和CSS文件来控制组件的外观。CSS文件必须显示地被包括在每一个HTML页面中:
<style type="text/css"> /* dojo.css is a CSS Reset, and is optional. @import "http://ajax.googleapis.com/ajax/libs/dojo/1.8/dojo/resources/dojo.css"; /* Using the claro theme in this example */ @import "http://ajax.googleapis.com/ajax/libs/dojo/1.8/dijit/themes/claro/claro.css"; /* Note that if you don't specify a minor revision, e.g. 1.8.0 or 1.7.1, the CDN will deliver the latest version */ </style>
在页面中的body标签中,或者在你的组件的父节点中,你需要根据你想要的主题定义class名。
<body class="claro">
你可以使用Dijit Theme Tester查看每一种主题。你也能够定义自己的主题。
在dojoConifg中有许多选项,但是最重要的两个是async和isDebug。在开发过程中你会想要将isDebug设置成true一边获得适当的警告信息。async选项用来告诉AMD Loader去使用全新的,快速的方法去加载JavaScript模块。
dojoConfig = { isDebug:true, async:true };
注意:parseOnLoad 是 dojoConfig 中的一个常用的选项,但是这个用法已经不再被推荐。请查看如下的关于 parser 的信息。
dojoConfig是全局的并且必须在你加载Dojo之前被载入,不然它会被忽略。你也可以将configuration设置为script文件上的一个属性,这种情况下你将使用data-dojo-config。
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.8/dojo/dojo.js" data-dojo-config="isDebug:true, async:true" type="text/javascript"> </script>
现在是时候来添加一个控件。一个快速的测试是在页面中添加一个按键,以便检验任何东西都如我们预料地进行。
<body class="claro"> <button data-dojo-type='dijit/form/Button'>Clicky</button> </body>
正如你看到的,控件并没有被正确地解析。我们需要载入dojo/parser 并且显式地告诉dojo去解析这个控件。我们何时做这件事?当让是在当DOM准备好之后。AMD式判断方法是使用dojo/domReady插件。 AMD被告知一个被载入的依赖是一个拥有感叹号的插件,比如:dojo/domReady!。因为我们不需要Dojo在解析之前做任何工作,我们可以安全地将这段代码放在body的底部。
<body class="claro"> <button data-dojo-type='dijit/form/Button'>Clicky</button> <script> require([ 'dojo/parser', 'dojo/domReady!' ], function(parser){ parser.parse(); // tell dojo to check the DOM for widgets }); </script> </body>
控件在claro主题下被解析,但是在控制台有一个警告:
WARNING: Modules being Auto-Required: dijit/form/Button.
这条警告是因为控件并未在任何地方被引入,为了是你的应用获得最佳的性能,AMD与Dojo需要你显式地定义你想在应用中使用的模块和依赖。Dojo1.8的解析器比较宽容。它异步并且足够聪明以至于能找到并且载入未被引入的模块。这是并不推荐使用的发放方法,因为这要比事先在你想要解析和渲染之前载入模块慢,但是它能够捕获错误并且在不阻塞应用的情况下告知我们还是很有用的。Dojo 1.7仅仅会失败并且提示一条错误信息。将dijit/form/Button加入require引用能够解决这个问题并且提高性能。
Dijit系统的一个最显著的特点是你可以使用一或两种方法创建一个Dijit控件:声明式,使用HTML标记和自定义的属性;或者编程式,使用纯粹的JavaScript。让我们看一看如何将一个基本select元素转变成一个Dojo-enhanced控件。
<select name="character" id="character"> <option value="">Select a character</option> <option value="Leonard">Dr. Leonard Leakey Hofstadter</option> <option value="Sheldon" selected="selected">Dr. Sheldon Lee Cooper</option> <option value="Rajesh">Dr. Rajesh Ramayan Koothrappali</option> <option value="Howard">Howard Joel Wolowitz</option> </select>
这是一个静态的包含了一系列options元素的select元素。我们知道我们想要将这个select元素变成一个dijit/form/FilterSelect控件,因此我们必须require这个模块。
require([ 'dojo/parser', 'dojo/domReady!', 'dijit/form/FilteringSelect' ], function(parser, domReady, FilteringSelect){ parser.parse(); });
既然dijit/form/FilterSelect模块已经可用,并且parser正在查找DOM中的控件,我们可以使用声明式或者编程式的方法来enhance我们的select元素。
声明式的增强select元素的方法是在HTML元素本身完成的。
<select name="character" id="characterNode" data-dojo-type="dijit.form.FilteringSelect" data-dojo-props='autoComplete:true, pageSize:10' > <option value="">Select a character</option> <option value="Leonard">Dr. Leonard Leakey Hofstadter</option> <option value="Sheldon" selected="selected">Dr. Sheldon Lee Cooper</option> <option value="Rajesh">Dr. Rajesh Ramayan Koothrappali</option> <option value="Howard">Howard Joel Wolowitz</option> </select>
这个声明式的例子阐述了data-dojo-type的使用以便标识出哪个Dijit应该被使用在给定的元素之上。当我们调用parser.parse()时, Dojo将会发现这个元素并且实例化并初始化控件。
dijit/form/FilteringSelect模块的选项也是自定义属性。当用户输入一个值之后控件会自动填入并且每一页显示10项。就像一个普通的select元素那样,“sheldon”会在初始被选中。
增强select元素的编程方法是完全使用Javascript完成的。
require([ 'dojo/domReady!', 'dijit/form/FilteringSelect' ], function(domReady, FilteringSelect){ var filteringSelect = new FilteringSelect({ autoComplete: true, pageSize: 10 },'characterNode'); });
require([ 'dojo/domReady!', 'dijit/form/FilteringSelect', 'dijit/form/Textbox', 'dijit/form/Textarea', 'dijit/form/Checkbox', 'dijit/form/RadioButton', ], function(domReady, FilteringSelect, Textbox, Textarea, RadioButton){ var filteringSelect = new FilteringSelect({ autoComplete: true, pageSize: 10 },'characterNode'); var input = new Textbox({/*options*/},'myInputNode'); var textarea = new Textarea({/*options*/},'myTextareaNode'); var mySelect = new FilteringSelect({/*options*/},'mySelectNode'); var date = new DateTextBox({/*options*/},'myDateNode'); var time = new TimeTextBox({/*options*/},'myTimeNode'); var checkbox = new CheckBox({/*options*/},'myCheckboxNode'); var radio1 = new RadioButton({/*options*/},'myRadio1Node'); var radio2 = new RadioButton({/*options*/},'myRadio2Node'); });
如果你有一个庞大的form并且不想将所有的单独元素加入dijit控件中,你可以创建自己的迷你parser以便通过选择器来创建Dijits.
require([ 'dojo/domReady!', 'dojo/query', 'dijit/form/FilteringSelect', 'dijit/form/Button', 'dijit/form/CheckBox', 'dijit/form/RadioButton' ], function(domReady, query, FilteringSelect, Button, CheckBox, RadioButton){ query('button,select,input').forEach(function(node){ var type = node.nodeName; if(type === 'INPUT'){ type = node.type.toUpperCase(); } switch(type){ case 'BUTTON': new Button({},node); break; case 'SELECT': new FilteringSelect({},node); break; case 'RADIO': new RadioButton({},node); break; case 'CHECKBOX': new CheckBox({},node); break; } }); });
当然,这个简单的例子并不是把node属性转换成变量并且将其提供给控件,也不是dojo/parser的任何特殊功能。
访问某一个特定的DOM元素可以简单地用dojo/dom.byId方法完成。Dijit有他自己的dijit/registry.byId方法来获取注册了ID的Dijit控件。如果dijit控件拥有一个ID,控件ID 将会是同一个值。如果元素没有一个ID属性,一个控件ID将会被自动生成。如果我们想要获取上面用声明方式创建的“characterNode” Dijit控件,我们可以使用如下的代码:
require([ 'dojo/domReady!', 'dojo/parser', 'dijit/registry', 'dijit/form/FilteringSelect' ], function(domReady, parser, registry, FilteringSelect){ parser.parse(); var filteringSelect = registry.byId('characterNode'); console.log('filteringSelect', filteringSelect); });
在firebug内使用registry.byId查看Dijit的所有方法和属性。
如果我们想要访问pageSize属性,我们可以用Dijit getter来访问:
var pageSize = registry.byId('characterNode').get('pageSize'); // returns 10
如果我们想要改变pageSize的值,可以使用如下代码:
registry.byId('characterNode').set('pageSize',20); //now pageSize is 20
Dijit控件使用dojo/on方法来监听给定控件上的DOM事件:
filteringSelect.on('change', function(value){ console.log('value', value); });
每个控件都支持一系列的事件所以请仔细查看文档以却确定你想要监听的事件是被支持的。
注意到它们是DOM事件是很重要的。如果你想要监听widget方法,你应该使用dojo/aspect:
require([ 'dojo/aspect' // other deps... ], function(aspect){ aspect.after(filteringSelect, 'validate', function(value){ console.log('validate', value); }); });
Dijit也是一个杰出的UI库,它有潜力来增强你的网站并且节约你很多的时间。Dijit包括许多控件,包括:
并且如果Dijit没有您需要的控件,很有可能在DojoX(Dojo Extensions)中有!如果想看上面提到的各种控件,请访问Dojo Theme Tester.