从基于浏览器的JavaScript受到关注时起,Document Object Model (DOM) 就是我们绘制所要内容的的地方,也是用户所看到的界面。如果我们想要增强、替换或是向浏览器加载好的HTML添加点什么东西,JavaScript和DOM便是我们所需要的。Dojo旨在使DOM操作变得更加简单、高效,为此Dojo提供了一些方便的函数来解决不同浏览器间恼人的的兼容性问题,并让常用操作更加简洁。
为了了解这些函数,我们将操作一个简单的页面,该页面中有一个含有五个元素的无序列表:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8">
- <title>Demo: DOM Functions</title>
- <mce:script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js" mce_src="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js"></mce:script>
- <mce:script type="text/javascript"><!--
- dojo.ready(function(){ // "ready" entry point
- });
- // --></mce:script>
- </head>
- <body>
- <ul id="list">
- <li id="one">One</li>
- <li id="two">Two</li>
- <li id="three">Three</li>
- <li id="four">Four</li>
- <li id="five">Five</li>
- </ul>
- </body>
- </html>
这个页面已经含有Dojo脚本标签, 相信你已经认识dojo.ready代码块。所有对DOM进行操作的代码必须等到DOM加载完毕后才能被执行。
检索
事有先后:为了对DOM进行操作,我们首先需要知道如何从DOM中获取元素。最简单的方法是使用dojo.byId。在你将一个你想要获得的元素的ID传给dojo.byId之后,如果ID相符的DOM节点存在,你将获得该节点,如果没有匹配的节点,那么将获得null。
这和使用document.getElementById是等价的,但是使用dojo.byId有两个优点:更简洁,并解决了某些浏览器对getElementById实现的bug。另一个dojo.byId很棒的特点是,如果你将一个DOM节点传给它,它将马上返回该节点。这有助于建立同时适用字符串与DOM节点的API。让我们来看一个例子:
- function setText(node, text){
- node = dojo.byId(node);
- node.innerHTML = text;
- }
- dojo.ready(function(){
- var one = dojo.byId("one");
- setText(one, "One has been set");
- setText("two", "Two has been set as well");
- });
setText函数用来设置一个节点的文字内容,由于dojo.byId可以接受DOM节点作为参数,该函数也就可以接受字符串或者DOM节点。
创建
另一个你会经常做的事情就是创建元素。Dojo不会阻止你使用原生的document.createElement方法来创建元素,但是创建一个元素并为其设置所有需要的属性可能会是非常冗长的。更可怕的是,你将面对不少不同浏览器差异造成的额外属性设置。而这使得dojo.create不可谓是一个更方便、可靠的选择。
dojo.create有如下参数:节点名(字符串)、节点的属性(object)、可选的父节点或是兄弟节点、可选的与父节点或是兄弟节点的相对位置(默认为“last”)。它返回新建的DOM元素节点。让我们看一个例子:
- dojo.ready(function(){
- var list = dojo.byId("list"),
- three = dojo.byId("three");
- dojo.create("li", {
- innerHTML: "Six"
- }, list);
- dojo.create("li", {
- innerHTML: "Seven",
- className: "seven",
- style: {
- fontWeight: "bold"
- }
- }, list);
- dojo.create("li", {
- innerHTML: "Three and a half"
- }, three, "after");
- });
一个简单的内容为“Six”的列表元素被创建并被添加到列表中。接着,另一个内容为“Seven”的列表元素被创建,它的className属性为”seven”,该样式使其字体为粗体,然后该元素被添加到列表中。最后,一个内容为“Three and a half”的列表元素被创建并被插入到ID为“three”的列表元素之后。
什么时候该像这样创建元素,什么时候该直接设置一个容器的innerHTML属性呢?如果你已经有一个你所需要的HTML内容的字符串时,设置innerHTML属性肯定会更快一点。但是,dojo.create的优势在你想要创建节点但又不需要立即将他们添加到DOM中,或是当你想要插入或是添加一个新元素而不影响周围的兄弟节点时就体现出来了。
安插
如果你已经有了一个节点并且想将安插到某处,你将会需要用到dojo.place。其参数如下:DOM节点或一个想要安插的节点的ID、DOM节点或是一个参照节点的ID、可选的位置(字符串,默认为“last”)。这和我们看到的dojo.create的参数表很像,事实上,dojo.create在底层使用了dojo.place。在前面的例子基础上,我们向页面加了几个按钮:
- <button onclick="moveFirst();">The first item</button>
- <button onclick="moveBeforeTwo();">Before Two</button>
- <button onclick="moveAfterFour();">After Four</button>
- <button onclick="moveLast();">The last item</button>
下面代码定义了一些使用dojo.place来移动列表中第三个节点的函数:
- function moveFirst(){
- var list = dojo.byId("list"),
- three = dojo.byId("three");
- dojo.place(three, list, "first");
- }
- function moveBeforeTwo(){
- var two = dojo.byId("two"),
- three = dojo.byId("three");
- dojo.place(three, two, "before");
- }
- function moveAfterFour(){
- var four = dojo.byId("four"),
- three = dojo.byId("three");
- dojo.place(three, four, "after");
- }
- function moveLast(){
- var list = dojo.byId("list"),
- three = dojo.byId("three");
- dojo.place(three, list);
- }
安插位置的有效参数可以是"before"、"after"、"replace"、"only"、"first"或"last"。有关每种安插选项的含义请参见reference guide for dojo.place 。
在这个简单的例子里,dojo.place比原生的parentNode.appendChild(node)稍稍多做了一点事情。它可以简单地指定安插的位置,无论是相对于父节点或是兄弟节点——使用一个一致的API。
删除
通常你会创建节点,不过有时候,你也会想要删除某些节点。Dojo提供了两种方法来删除节点:dojo.destory会删除一个节点和其所有的子节点,而dojo.empty将只删除一个节点的子节点。这两种方法都接受一个DOM节点或是一个节点的ID作为参数。我们将向我们的页面添加两个按钮:
- <button onclick="destroyFirst();">Destroy the first list item</button>
- <button onclick="destroyAll();">Destroy all list items</button>
- function destroyFirst(){
- var list = dojo.byId("list"),
- items = list.getElementsByTagName("li");
- if(items.length){
- dojo.destroy(items[0]);
- }
- }
- function destroyAll(){
- dojo.empty("list");
- }
第一个按钮在用户按下时删除列表中的第一个元素。第二个按钮则清空整个列表。