DOM详解
前言
DOM(文档对象模型),用来将HTML和XML文档描绘成一个层次化的节点数,允许开发人员添加、删除或修改页面的内容。IE中的DOM对象是通过COM对象的形式实现的,因此IE的DOM对象与JS对象的行为特点并不一致。
节点类型
常见的四个节点类型:Node.ELEMENT_NODE(1)、Node.ATTRIBUTE_NODE(2)、Node.TEXT_NODE(3)、Node.DOCUMENT_NODE(9)。
在IE8-中不能直接访问节点类型名称(Node.ELEMENT_NODE)。在判断节点类型时最好以数字值(1)比较。
1 <div id="div"></div> 2 <script> 3 console.log(document.getElementById('div').nodeType); // 1 4 console.log(document.getElementById('div').nodeType == Node.ELEMENT_NODE); // true IE8-中会报错Node未定义 5 console.log(document.getElementById('div').nodeType == 1); // true 6 </script>
nodeName:
元素节点的nodeName是标签名;
属性节点的nodeName是属性名;
文本节点的nodeName始终是#text;
文档节点的nodeName始终是#document。
1 <div id="div">11</div> 2 <script> 3 console.log(document.getElementById('div').nodeName); // DIV 4 console.log(document.getElementById('div').getAttributeNode('id').nodeName); // id 5 console.log(document.getElementById('div').childNodes[0].nodeName); // #text 6 console.log(document.nodeName); // #document 7 </script>
nodeValue:
文本节点的nodeValue是文本内容;
属性节点的nodeValue是属性值;
元素节点的nodeValue是null,
文档节点的nodeName是null。
1 <div id="div">11</div> 2 <script> 3 console.log(document.getElementById('div').nodeValue); // null 4 console.log(document.getElementById('div').getAttributeNode('id').nodeValue); // div 5 console.log(document.getElementById('div').childNodes[0].nodeValue); // 11 6 console.log(document.nodeValue); // null 7 </script>
NOTE:在通过nodeName来检查是否为某元素时最好先检测nodeType等于1。
节点关系
childNodes:
childNodes可以动态执行查询结果,当DOM结构变化时能自动反映出来。
可以通过方括号或item()方法来访问childNodes中的某个节点。
1 <div id="div"> 2 11 3 <span>11111111</span> 4 22 5 </div> 6 <script> 7 console.log(document.getElementById('div').childNodes); // 如下图 8 console.log(document.getElementById('div').childNodes[1].nodeType); // 1 9 console.log(document.getElementById('div').childNodes.item(1).nodeType); // 1 10 console.log(document.getElementById('div').childNodes.length); // 3 11 document.getElementById('div').innerHTML += '<span>22222222</span>'; 12 console.log(document.getElementById('div').childNodes.length); // 4 13 </script>
如图所示:后添加一个span也能动态的显示在childNodes中。
parentNode:父节点
previousSibling:上一个兄弟节点(上一个没有就是null)
nextSibling:下一个兄弟节点(下一个没有就是null)
firstChild:第一个子节点(没有子节点为null)
lastChild:最后一个子节点(没有子节点为null)
hasChildNodes:有一个或多个子节点时返回true,比查询childNodes.length更高效。
1 <div id="div1"></div> 2 <div id="div2"> </div> 3 <div id="div3"> 4 5 6 </div> 7 <script> 8 console.log(document.getElementById('div1').hasChildNodes()); // false 9 console.log(document.getElementById('div2').hasChildNodes()); // true IE8- false(在IE8-空文本不会当作节点,标准浏览器是节点) 10 console.log(document.getElementById('div3').hasChildNodes()); // true IE8- false(在IE8-空文本不会当作节点,标准浏览器是节点) 11 </script>
ownerDocument:该属性指向文档节点。当访问文档节点时可以通过节点的这个属性来查找提升效率。
1 <div id="div1"></div> 2 <script> 3 console.log(document.getElementById('div1').ownerDocument); // #document 4 </script>
操作节点
appendChild:在childNodes末尾添加一个节点,返回新增的节点,如果新节点是已有的节点那么该节点的原位置会被删除。
1 <div id="div">div</div> 2 <ul id="ul"> 3 <li id="li1">1</li> 4 <li id="li2">2</li> 5 <li id="li3">3</li> 6 </ul> 7 <script> 8 var oLi = document.createElement('li'), 9 oUl = document.getElementById('ul'), 10 oDiv = document.getElementById('div'), 11 oLi1 = document.getElementById('li1'); 12 oLi.innerHTML = '4'; 13 14 console.log(oUl.appendChild(oLi)); // <li>4</li> 返回新增的元素 15 console.log(oUl.appendChild(oLi1)); // <li id="li1">1<div id="div">div</div></li> 返回新增的元素 动态显示了div 16 console.log(oLi1.appendChild(oDiv)); // <div id="div">div</div> 返回新增的元素 17 </script>
最后的DOM结构:
insertBefore:插入节点。返回被插入的节点。如果参照节点为null,insertBefore和appendChild一样。
1 <ul id="ul"> 2 <li id="li1">1</li> 3 <li id="li2">2</li> 4 <li id="li3">3</li> 5 </ul> 6 <script> 7 var oLi = document.createElement('li'), 8 oUl = document.getElementById('ul'); 9 oLi.innerHTML = '4'; 10 11 console.log(oUl.insertBefore(oLi, null)); // <li>4</li> 返回被插入的元素 插入最后 12 console.log(oUl.insertBefore(oLi, oUl.firstChild)); // <li>4</li> 返回被插入的元素 插入前面 13 console.log(oUl.insertBefore(oLi, oUl.lastChild)); // <li>4</li> 返回被插入的元素 插入最后一个的前面 14 </script>
replaceChild:替换节点。返回被替换的节点。节点被替换后,该节点还是存在文档中,如果节点不适用了应当将其销毁。
1 <ul id="ul"><li id="li1">1</li><li id="li2">2</li><li id="li3">3</li></ul> 2 <script> 3 var oLi = document.createElement('li'), 4 oUl = document.getElementById('ul'); 5 oLi.innerHTML = '4'; 6 7 console.log(oUl.replaceChild(oLi, oUl.firstChild)); // <li id="li1">1</li> 返回被替换的元素 8 console.log(oUl.replaceChild(oLi, oUl.lastChild)); // <li id="li3">3</li> 返回被替换的元素 9 </script>
removeChild:删除节点。返回被删除的节点。节点被删除后,该节点还是存在文档中,如果节点不适用了应当将其销毁。
cloneNode:复制节点。可以传递一个boolean值,true深度复制会复制所有的子节点,false浅度赋值不会复制子节点。该方法不能复制通过js添加的属性和事件。
1 <ul id="ul"><li id="li1">1</li><li id="li2">2</li><li id="li3">3</li></ul> 2 <script> 3 var oUl = document.getElementById('ul'); 4 5 console.log(oUl.cloneNode(false)); // <ul id="ul"></ul> 浅度复制 6 console.log(oUl.cloneNode(true)); // <ul id="ul"><li id="li1">1</li><li id="li2">2</li><li id="li3">3</li></ul> 深度复制 7 </script>
1 <ul id="ul" onclick="alert(1)"><li id="li1">1</li><li id="li2">2</li><li id="li3">3</li></ul> 2 <script> 3 var oUl = document.getElementById('ul'); 4 oUl.onmouseover = function(){this.style.background = 'red';} // 该事件未被复制 5 6 console.log(oUl.cloneNode(false)); // <ul id="ul"></ul> 浅度复制 7 console.log(oUlClone = oUl.cloneNode(true)); // <ul id="ul"><li id="li1">1</li><li id="li2">2</li><li id="li3">3</li></ul> 深度复制 8 9 document.body.appendChild(oUlClone); // onclick事件被复制了 10 </script>
document类型
1、访问html:document.documentElement、document.firstChild、document.childNodes[0] 其中document.documentElement的效率最高
2、访问body:document.body
3、文档类型:document.doctype(兼容性很差)
4、title属性:document.title
5、URL地址:document.URL
6、域名:document.domain
7、链接到当前页面的页面:document.referrer
1 console.log(document.URL); // url 2 console.log(document.domain); // 域名 3 console.log(document.referrer); // 链接到本页的url
8、getElementById:根据元素ID获取元素,没有返回null。
1、IE8-的id不区分大小写,标准浏览器区分大小写。
2、页面多个元素id相同时,返回第一个。
3、IE7-中表单元素的name值与某个元素的ID值相同时,如果name在前会返回name对应的表单元素。
1 <div name="test" class="div1"></div><!-- IE7- div的name不能获取 --> 2 <input type="button" name="test" class="button1"/> 3 <div id="test" class="div2"></div> 4 <script> 5 console.log(document.getElementById('test').className); // div2 IE7- button1 6 </script>
9、getElementsByTagName:获取的元素是动态的,可以通过[index]、[name]、item(index)、namedItem(name)方法来访问某个元素。
1 <img name="test1"> 2 <img name="test2"> 3 <img name="test3"> 4 <img name="test4"> 5 <script> 6 console.log(document.getElementsByTagName('img')[0].name); // test1 7 console.log(document.getElementsByTagName('img')['test1'].name); // test1 8 console.log(document.getElementsByTagName('img').item(0).name); // test1 9 console.log(document.getElementsByTagName('img').namedItem('test1').name); // test1 10 </script>
一些集合:
1、document.anchors:返回页面中带有name属性的a元素;
2、document.forms:返回页面中的所有form元素;
3、document.images:返回页面中的所有img元素;
4、document.links:返回页面中所有带href属性的a元素。
元素类型
1、tagName/nodeName:返回元素的标签名(注意返回的值可能是大写也可能是小写)。
2、getAttribute、setAttribute、removeAttribute操作元素的属性
①、此时的class就直接用class而不用className
②、属性名不区分大小写
③、在html5中规定自定义属性名加上data-以便通过验证
④、通过getAttribute获取style和事件处理函数返回的是字符串代码,而通过DOM.style和DOM.onclick返回的确是对象和函数
⑤、通过DOM.设置的自定义属性值,通过getAttribute来获取只能得到null
1 <div id="div" style="font-size: 20px;">div</div> 2 <script> 3 var oDiv = document.getElementById('div'); 4 oDiv.onclick = function(){ 5 console.log(this.tagName); 6 }; 7 console.log(typeof oDiv.getAttribute('onclick')); // object null(IE7-两种方法返回值一样) 8 console.log(typeof oDiv.onclick); // function 9 console.log(typeof oDiv.getAttribute('style')); // string (IE7-两种方法返回值一样) 10 console.log(typeof oDiv.style); // object 11 </script>
1 <div id="div">div</div> 2 <script> 3 var oDiv = document.getElementById('div'); 4 oDiv.index = 1; 5 console.log(oDiv.getAttribute('index')); // null(IE8-两种方法返回值一样) 6 console.log(oDiv.index); // 1 7 </script>
3、removeAttribute:IE6不支持。