为什么要学节点操作
在DOM中获取元素通常使用两种方式:
- 利用DOM提供的方法获取元素,比如document.getElementByld()、document.getElementsByTagName()等。这种方式逻辑性强,但是兼容性稍差。
- 利用节点层级关系获取元素。比如利用父子兄节点关系获取元素,这种方式更为简单些。
什么是节点
网页中的所有内容都是节点
(标签、属性、文本、注释等) , 在DOM中,节点使用node
来表示。HTML DOM树中的所有节点均可通过JavaScript进行访问,有HTML元素(节点)均可被修改,也可以创建或删除。
一般地, 节点
至少拥有nodeType
(节点类型)、nodeName
(节点名称)和nodeValue
(节点值)这三个基本属性。
- 元素节点nodeType为1
- 属性节点nodeType为2
- 文本节点nodeType为3 (文本节点包含文字、空格、换行等)
在实际开发中,节点操作主要操作的是元素节点
节点层级
利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。
1. 父级节点 node.parentNode
- parentNode 属性可返回某节点的父节点,注意是最近的一个父节点
- 如果指定的节点没有父节点则返回null
<body>
<div class="box">
<div class="nav">
<span>123</span>
</div>
</div>
<script>
var span = document.querySelector('span');
// 得到的是离 span最 近的父节点 nav 如果找不到 则返回null
console.log(span.parentNode);
</script>
</body>
2. 子节点
1) parentNode.childNodes(标准)
parentNode.childNodes
返回包含指定节点的子节点的集合,该集合为即时更新的集合。
注意: 返回值里面包含了所有的子节点,包括元素节点,文本节点等。
如果只想要获得里面的元素节点,则需要专门处理。所以一般不提倡使用childNodes
<body>
<ul>
<li>1</li>
<li>2</li>
</ul>
<script>
var ul = document.querySelector('ul');
// 获取ul里面的全部li,但是返回值里面包含了元素节点、文本节点(换行、空格等)。
console.log(ul.childNodes);
</script>
</body>
输出结果:
2) parentNode.children(非标准)
parentNode.children
是一个只读属性,返回所有的子元素节点
,其余节点不返回。
虽然children是一个非标准 ,但是得到了各个浏览器的支持,因此可以放心使用
子节点 | 描述 |
---|---|
parentNode.firstChild | 返回第一个子节点,找不到则返回null。同样,也是包含所有的节点 |
parentNode.lastChild | 返回最后一个子节点,找不到则返回null。同样,也是包含所有的节点。 |
parentNode.firstElementChild | 返回第一个子元素节点,找不到则返回null。有兼容性问题,IE9以上才支持 |
parentNode.lastElementChild | 返回最后一个子元素节点,找不到则返回null。有兼容性问题,IE9以上才支持 |
实际开发中,firstChild
和lastChild
包含其他节点,操作不方便,而firstElementChild
和lastElementchild
又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?
解决方案:
1.如果想要第一个子元素节点,可以使用parentNode.children[0]
2. 如果想要第一个子元素节点,可以使用parentNode.chilren[parentNode.children.lenth - 1]
3. 兄弟节点
兄弟节点 | 描述 |
---|---|
node.nextSibling | 返回当前元素的下一个兄弟节点,找不到则返回nu1l。同样,也是包含所有的节点 |
node.previousSibling | 返回当前元素上一个兄弟节点,找不到则返回null。同样,也是包含所有的节点。 |
node.nextElementsibling | 返回当前元素下一个兄弟元素节点,找不到则返回null。有兼容性问题,IE9 以上才支持 |
node.previousElementsibling | 返回当前元素上一个兄弟节点,找不到则返回null。有兼容性问题,IE9 以上才支持 |
解决兼容性方案: 自己封装一个函数
function getNextElementSibling (element) {
var el = element ;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
创建和添加节点
-
创建节点
document.createElement ( 'tagName ')
方法创建由tagName
指定的HTML元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。 -
添加节点
node.appendChild()
方法将一个节点添加到指定父节点node
的子节点child
列表末尾。类似于css里面的after伪元素。
node.insertBefore (child,指定元素)
方法将一个节点添加到父节点的指定子节点前面。类似于css里面的before伪元素
<body>
<ul>
<li>1</li>
</ul>
<script>
//1.创建元素 节点
var a = document.querySelector('a');
//2.添加元素节点
var ul = document.querySelector('ul');
ul.appendChild(a); //在ul 里面添加了一个a链接
//3. 利用node.insertBefore (child,指定元素) 添加节点
var li = document.querySelector('li');
ul.insertBefore(li,ul.children[1]);//在ul第二个元素前面添加一个li
</script>
</body>
删除节点
node. removeChild()
方法从DOM中删除一个子节点,返回删除的节点。
复制节点
node.cloneNode ()
方法返回调用该方法的节点的一个副本。也称为克隆节点 / 拷贝节点
注意:
1.如果括号参数为空或者为false
,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点。
2.如果括号参数为true
,则是深度拷贝会复制节点本身以及里面所有的子节点。
<script>
var ul = document.querySelector('ul');
var lis = ul.children[0].cloneNode(true);//深拷贝
var lili = ul.children[0].cloneNode();//浅拷贝
ul.appendChild(lis);// 添加的是 <li>1</li>
ul.appendChild(lili);// 添加的是 <li></li>
</script>
三种动态创建元素区别
- document. write ()
- element. innerHTML()
- document.createElement ()**
document.write
是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘innerHTML
是将内容写入某个DOM节点,不会导致页面全部重绘innerHTML
创建多个元素效率更高(不要拼接字符串,采取数组形式拼接) , 结构稍微复杂createElement()
创建多个元素效率稍低一点点,但是结构更清晰
<script>
// 1. innerHTML 创建元素
var nav = document.querySelector('.nav');
nav.innerHTML = '<a href="javascript:;">百度</a>';
var arr = []; // 采用数组形式拼接
for (var i = 0;i < 100;i++){
arr.push('<a href="javascript:;">百度</a>');
}
nav.innerHTML = arr.join('');//将数组中所有元素连接为一个字符串
</script>
总结: 不同浏览器下,innerHTML效率要比creatElement高