1、节点
页面中所有内容都是节点:标签、属性、文本、注释等,在DOM中,节点用node
来表示
HTML DOM 树中的所有节点均可通过JavaScript进行访问,所有HTML元素(节点)均可被修改,也可以创建或删除
一般地,节点至少拥有 nodeType(节点类型)、nodeName(节点名称) 和 nodeValue(节点值)这三个基本属性
- 元素节点 nodeType 为 1
- 属性节点 nodeType 为 2
- 文本节点 nodeType 为 3 (文本节点包含文字、空格、换行等)
<div id="you">你能不能温柔提醒</div>
复制代码
- 元素节点:
<div></div>
- 属性节点:
id='you'
- 文本节点:你能不能温柔提醒
2、节点层级
利用 DOM 树可以把节点划分为不同的层级关系,常见的是父子兄层级关系
2.1 父节点
node.parentNode
复制代码
栗子:
<div class="parent">
<div class="son"></div>
</div>
复制代码
let son = document.querySelector('.son');
// 获取最近一级的父元素,如果找不到父节点就返回null
console.log(son.parentNode);
复制代码
2.2 子节点
parentNode.childNodes;
复制代码
- 标准
- 返回包含指定节点的集合,该集合为即使更新的集合
返回值里面包含了所有的子节点,包括元素节点、文本节点等
let parent = document.querySelector('.parent');
console.log(parent.childNodes); // [text, div.son, text]
复制代码
text
是换行- 如果想要获取里面的元素,需要在过滤一遍,所以一般不使用
childNodes
过滤元素节点
for (var i = 0; i < box.childNodes.length; i++) {
// 过滤掉文本节点
if (box.childNodes[i] === 1) {
console.log(box.childNodes[i]);
}
}
复制代码
parentNode.children
- 是一个只读属性,返回所有的子元素节点,其余节点不返回
- 非标准
虽然 children
是一个非标准,但是得到各浏览器的支持,因此我们可以放心使用
let parent = document.querySelector('.parent');
console.log(parent.children); // [div.son]
复制代码
获取第n个节点
firstChild
返回的是第一个子节点,找不到则返回null。同样,也是包含所有的节点
parentNode.firstChild // 获取第一个子节点
复制代码
firstChild
返回的是最后一个子节点,找不到则返回null。同样,也是包含所有的节点
parentNode.lastChild // 获取最后一个子节点
复制代码
栗子:
<ul>
<li>1</li>
<li>2</li>
</ul>
复制代码
var ul = document.querySelector('ul');
console.log(ul.firstChild); // #text
console.log(ul.lastChild); // #text
复制代码
但是上面两个获取到的是 文本节点
但是,我们可以用以下的方法:
// 获取第一个子节点
parentNode.firstElementChild;
// 获取最后一个子节点
parentNode.firstElementChild;
复制代码
注意:这两个方法有兼容性问题,IE9 以上才支持
所以,为了解决兼容新问题和返回第n个子节点的做法,我们直接使用children
console.log(ul.children[0]); // <li>1</li>
console.log(ul.children[1]); // <li>2</li>
复制代码
总结:
parentNode
和parentElement
功能一样,childNodes
和children
功能一样parentNode
和childNodes
是符合W3C标准的,可以说比较通用。而另外两个只是IE支持,不是标准,Firefox就不支持。- 我们一般使用
parentNode
和children
2.3 兄弟节点
nextSibling
返回当前元素的下一个兄弟节点,找不到,找不到则返回 null
,同样,也是包含所有的节点
node.nextSibling
复制代码
previousSibling
返回当前元素的上一个兄弟节点,找不到,找不到则返回 null
,同样,也是包含所有的节点
node.previousSibling
复制代码
只获取元素节点
node.nextElementSibling // 获取下一个元素
node.previousElementSibling // 获取上一个元素
复制代码
- 这两个方法都有兼容性,IE9以上的才支持
栗子:
<div>我是div</div>
<span>我是span</span>
复制代码
var div = document.querySelector('div');
// nextSibling 获取的是换行符 即文本节点
console.log(div.nextSibling); // #text
console.log(div.previousSibling); // text
// nextElementSibling 获取元素
console.log(div.nextElementSibling); // <span>我是span</span>
console.log(div.previousElementSibling); // null
复制代码
解决兼容性问题:封装一个函数
function getNextElementSibling(element) {
let el = element
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el
}
}
}
复制代码
3、创建和添加节点
创建节点
document.createElement('tagName');
复制代码
document.createElement()
方法创建有tagName
指定的HTML元素,因为这些元素先不存在,是根据我们需求动态生成的,所以我们也称为 动态创建元素节点
添加元素
node.appenchild(child) // node 是父级,child 是子级
复制代码
node.appendChild()
方法将一个节点添加到指定父节点的子节点列表末尾。类似于 css 里面的 after
伪元素
node.insertBefore(child, 指定元素)
复制代码
node.insertBefore()
方法将一个节点添加到父节点的指定子节点前面。类似于 css 里面的 before
伪元素
栗子:
<ul>
<li>1</li>
</ul>
复制代码
// 1、创建节点元素点
var li = document.createElement("li");
// 2、添加节点
var ul = document.querySelector('ul');
ul.appendChild(li); // 添加在子节点的尾部
// 3、添加节点
var li1 = document.createElement('li');
ul.insertBefore(li1, ul.children[0]);
复制代码
- 添加节点前要先创建节点
4、删除节点
node.removeChild(child)
复制代码
node.removeChild()
方法从 node
中删除一个子节点,返回删除的节点
5、复制节点
node.cloneNode()
复制代码
node.cloneNode()
方法返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点
注意:
- 如果括号参数为 空 或者为
false
,则是 “浅拷贝”;即只复制节点本身,不赋值里面的子节点 - 如果括号为
true
,则是“深拷贝”,会复制节点本身及里面所有的子节点
let ul = document.querySelector('ul');
// 克隆 (复制)
let li = ul.children[0].cloneNode(true);
// 添加(粘贴)
ul.appendChild(li);
复制代码
6、三种动态常见元素节点
6.1 document.write()
document.write()
是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
<button>按钮</button>
<div class="inner"></div>
<p class="creat"></p>
复制代码
// 1、document.write() 创建元素
document.write('<div>123</div>');
// 如果页面文档流加载完毕,在调用这句话会导致页面重绘
var btn = document.querySelector('button');
btn.onclick = function() {
document.write('<div>123</div>');
}
复制代码
当我们点击按钮的时候,文档流已经加载完毕,所以会导致重绘,即页面内容会被 document.write
覆盖
- 页面重绘就是:如果其他元素加载完毕后,
document.write()
再加载(上面就是在点击按钮之后再显示),页面其他元素就会被清除掉,只显示document.write()
添加进来的元素 - 所以实际上级开发中比较少用
6.2 innerHTML
和 “createElement()`
innerHTML
是将内容写入某个DOM
节点,不会导致页面全部重绘innerHTML
创建多个元素效率效率更高(不要拼接字符,采用数组的形式拼接),结构稍微复杂createElement()
创建多个元素效率稍微低一点点,但是结构清晰createElement()
常与appendChild
或insertBefore
搭配使用