DOM(Document Object Model)
DOM介绍
DOM树
HTML加载完毕后会生成一个DOM树
- html、head、body、a等节点称为元素节点
- href等节点称为属性节点
- innerHTML等节点称为文本节点
节点类型
<div>
<!-- 注释 -->text1
text2
<p>段落</p>
</div>
假设父元素是div标记,则:
- 第一行
<div>
后的换行
和制表符
被划分为一个文本节点(#text) - 第二行的
<!-- 注释 -->
是一个注释节点(#comment) - 第二行
<!-- 注释 -->
后的text1
和换行
和制表符
和text2
和换行
被划分为一个文本节点 - 第三行的
<p>段落</p>
是一个元素节点 - 第三行的
<p>段落</p>
后的换行
是一个文本节点
所以div一共有5个子节点
获取DOM节点
获取节点
获取元素节点
//单个
document.getElementById();
//数组
document.getElementsByClassName();
document.getElementsByTagName();
获取属性节点
元素节点.getAttributeNode(attributeName);
节点的常用属性
例:
<div id="d">this is a div<!-- 注释 --></div>
var d=document.getElementById("d");
console.log(d.firstChild);
输出:
nodeName: "#text" //节点名(文本节点)
nodeType: 3 //节点类型(1:元素 2:属性 3:文本)
nodeValue: "this is a div" //节点value
parentNode: HTMLDivElement //父节点
parentElement: HTMLDivElement //父元素节点
previousSibling: null //上一个兄弟节点
nextSibling: Comment //下一个兄弟节点(注释)
length: 13 //长度
...
节点间关系
父节点
节点.parentNode
子节点
第一个子节点
IE6、7、8仅支持firstChild
fireFox、Chrome、IE9+支持firstChild和firstElementChild
IE6、7、8中的firstChild指第一个子标签节点
fireFox、Chrome、IE9+中的firstChild指第一个子节点(包括换行、标签、空文档)
fireFox、Chrome、IE9+中的firstElementChild指第一个子标签节点
所以考虑兼容性:
//IE 6、7、8
节点.firstChild
//fireFox、Chrome、IE9+
节点.firstElementChild
两个属性可以这样合并:
var 第一个子节 = 点节点.firstElementChild || 节点.firstChild
//优先使用firstElementChild,若是IE 6、7、8,因为不支持所以会用后者;而其他浏览器则会使用前者
最后一个子节点
同上具有兼容性问题,语句为:
节点.lastChild
节点.lastElementChild
所有子节点
标准属性:childNodes
IE6、7、8中的childNodes指所有子元素节点
fireFox、Chrome、IE9+中的childNodes指所有子节点(包括换行、标签、空文档)
非标准属性(虽不是标准属性,但几乎所有浏览器都支持):children
fireFox、Chrome、IE9+中的children指所有子元素节点
IE6、7、8中的children还包含了注释节点,要注意注释不要写操作节点里面
使用时建议用children(注意不要写注释节点)来达到多浏览器兼容
兄弟节点
下一个兄弟节点
同获取第一个子节点一样具有兼容性问题,语句为:
节点.nextSibling
节点.nextElementSibling
上一个兄弟节点
同获取第一个子节点一样具有兼容性问题,语句为:
节点.previousSibling
节点.previousElementSibling
操作DOM节点
创建节点
var a=document.createElement("div");
var b=document.createElement("abc");
console.log(a); //<div></div>
console.log(b); //<abc></abc>
console.log(typeof a); //object
console.log(typeof b); //object
插入(移动)节点
appendChild
在指定节点内的最后插入
节点.appendChild(object)
insertBefore
在指定节点内的参考节点前插入,若找不到参考节点则按appendChild插到最后
节点.insertBefore(object,参考节点)
移动节点
<div id="d1">
<p>1</p>
</div>
<div id="d2">
<p>2</p>
</div>
var d1=document.getElementById("d1");
var p2=document.getElementById("d2").firstElementChild;
d1.appendChild(p2); //p2移动到d1
d1.insertBefore(p2,d1.firstElementChild); //p2移到p1前面
删除节点
格式:
父节点.removeChild(object)
若要删除自己,可以:
node.parentNode.removeChild(node)
复制节点
格式:
节点.cloneNode(Boolean)
参数为false(默认为false)时,表示仅复制节点本身
参数为true时,表示复制还所有子节点
例:
<div>
111
<a>baidu</a>
</div>
为true时复制全部
为false时仅复制:<div></div>
,任何子节点都不复制(不仅只有元素节点)
操作节点属性
获取属性
例:
<img src="1.jpg" id="i1" class="imgs" alt="img1" />
var i1=document.getElementById("i1");
直接操作
i1.src 或 i1["src"] --> http://localhost/test/1.jpg
i1.className 或 i1["className"] --> imgs
i1.alt 或 i1["alt"] --> img1
i1.width 或 i1["width"] --> 63
直接操作获取的src是绝对路径,因为直接读取的是系统属性
class要写为className,因为系统中存储的是className属性
获取width时虽然标签中没有声明,但因为是读取系统属性所以仍可以读出来
作为节点操作
i1.getAttribute("src") --> 1.jpg
i1.getAttribute("class") --> imgs
i1.getAttribute("alt") --> img1
i1.getAttribute("width") --> null
使用getAttribute相当于直接读取html文档中的属性节点,不是读取系统属性
所以获取src和class时不用考虑系统属性名和系统中属性值是否与html文档相同的问题
读取width时因为标签中没有声明,所以找不到width,此时应该用直接操作
删除属性
格式:
node.removeAttribute(attribute)
设置属性
格式:
node.setAttribute(attribute,value)
直接操作和作为节点操作注意事项
直接操作操作的是系统中的属性,作为节点操作操作的是标签上的属性节点
例子:
i1.a="abc";
console.log(i1.a); //abc
console.log(i1.getAttribute("a")); //null
i1.setAttribute("b","def");
console.log(i1.b); //undefined
console.log(i1.getAttribute("b")); //def
所以两者不可混用
innerHTML和innerText的区别
<div id="d">
aaa
<div>
div2
</div>
</div>
上面的HTML片段中,运行以下打码:
console.log(d1.innerText); // aaa div2
console.log(d1.innerHTML); //2-5行全部输出
d1.innerText="<p>text</p>"; //此时的 < > 被作为字符串被转换为 < >
console.log(d1.innerHTML); //<p>text</p>
//!在设置 文本节点 时同时覆盖了所有 其他节点
d1.innerHTML="<p>text</p>"; //p标签作为正常的元素节点,不会被转换