- 网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM 中,节点使用 node 来表示。
- HTML DOM 树中的所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
1. 父级节点
- 每个节点都有一个 parentNode 属性,指向其 DOM 树中的父元素。
- childNodes 中的所有节点都有同一个父元素,因此它们的 parentNode 属性都指向同一个节点。
- 此外,childNodes 列表中的每个节点都是同一列表中其他节点的同胞节点。
<div class="demo">
<div class="box">
<span class="erweima">×</span>
</div>
</div>
<script>
// 1. 父节点 parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('.box');
// 得到的是离元素最近的父级节点(亲爸爸) 如果找不到父节点就返回为 null
console.log(erweima.parentNode);
</script>
2. 子节点
- 每个节点都有一个 childNodes 属性,其中包含一个 NodeList 的实例(伪数组)。 NodeList 是一个类数组对象,用于存储可以按位置存取的有序节点。
- 注意,NodeList 并不是 Array 的实例,但可以使用中括号访问它的值,而且它也有 length 属性。
- NodeList 对象独特的地方在于,它其实是一个对 DOM 结构的查询,因此 DOM 结构的变化会自动地在 NodeList 中反映出来。
- 我们通常说 NodeList 是实时的活动对象,而不是第一次访问时所获得内容的快照(即静态数组)。
如果元素的子节点类型全部是元素类型,那 children 和 childNodes 中包含的节点应该是一样的。可以像下面这样使用 children 属性:
let childCount = element.children.length;
let firstChild = element.children[0];
第一个子节点
最后一个子节点
第一个元素子节点
最后一个元素子节点
实际开发中,firstChild 和 lastChild 包含其他节点,操作不方便,而 firstElementChild 和 lastElementChild 又有兼容性问题,
3. 兄弟节点
- 每个节点都有一个 parentNode 属性,指向其 DOM 树中的父元素。
- childNodes 中的所有节点都有同一个父元素,因此它们的 parentNode 属性都指向同一个节点。
- 此外,childNodes 列表中的每个节点都是同一列表中其他节点的兄弟节点。
- 而使用 previousSibling 和 nextSibling 可以在这个列表的节点间导航。
- 这个列表中第一个节点的 previousSibling 属性(q前一个兄弟节点)是 null,最后一个节点的nextSibling 属性(后一个兄弟节点)也是 null
注意,如果 childNodes 中只有一个节点,则它的 previousSibling 和 nextSibling 属性都是null。<div>我是div</div> <span>我是span</span> <script> var div = document.querySelector('div'); // 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等 console.log(div.nextSibling); console.log(div.previousSibling); // 2. nextElementSibling 得到下一个兄弟元素节点 console.log(div.nextElementSibling); console.log(div.previousElementSibling); </script>
4. 创建节点
let div = document.createElement("div");
5. 插入节点
appendChild(),用于在 childNodes 列表末尾添加节点。添加新节点会更新相关的关系指针,包括父节点和之前的最后一个子节点。appendChild()方法返回新添加的节点
let returnedNode = someNode.appendChild(newNode);
alert(returnedNode == newNode); // true
alert(someNode.lastChild == newNode); // true
如果把文档中已经存在的节点传给 appendChild(),则这个节点会从之前的位置被转移到新位置。即使 DOM 树通过各种关系指针维系,一个节点也不会在文档中同时出现在两个或更多个地方。因此,如果调用 appendChild()传入父元素的第一个子节点,则这个节点会成为父元素的最后一个子节点,
如下所示:
// 假设 someNode 有多个子节点
let returnedNode = someNode.appendChild(someNode.firstChild); //将第一个节点插入到最后一个去
alert(returnedNode == someNode.firstChild); // false 不在第一个了
alert(returnedNode == someNode.lastChild); // true 确认在最后一个
- 如果想把节点放到 childNodes 中的特定位置而不是末尾,则可以使用
insertBefore()
方法 - 这个方法接收两个参数:要插入的节点和参照节点。
- 调用这个方法后,要插入的节点会变成参照节点的前一个兄弟节点,并被返回。
- 如果参照节点是 null,则 insertBefore()与 appendChild()效果相同
// 作为最后一个子节点插入 returnedNode = someNode.insertBefore(newNode, null); alert(newNode == someNode.lastChild); // true // 作为新的第一个子节点插入 returnedNode = someNode.insertBefore(newNode, someNode.firstChild); alert(returnedNode == newNode); // true alert(newNode == someNode.firstChild); // true // 插入最后一个子节点前面 returnedNode = someNode.insertBefore(newNode, someNode.lastChild); alert(newNode == someNode.childNodes[someNode.childNodes.length - 2]); // true
appendChild()
和insertBefore()
在插入节点时不会删除任何已有节点。相对地,replaceChild()
方法接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之。
replaceChild()
方法:
// 替换第一个子节点
let returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
// 替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);
使用 replaceChild()插入一个节点后,所有关系指针都会从被替换的节点复制过来。虽然被替换的节点从技术上说仍然被同一个文档所拥有,但文档中已经没有它的位置。
6. 删除节点
要移除节点而不是替换节点,可以使用removeChild()
方法。这个方法接收一个参数,即要移除 的节点。被移除的节点会被返回,
// 删除第一个子节点
let formerFirstChild = someNode.removeChild(someNode.firstChild);
// 删除最后一个子节点
let formerLastChild = someNode.removeChild(someNode.lastChild);
7. 复制节点
- 第一个是 cloneNode(),会返回与调用它的节点一模一样的节 点。
- cloneNode()方法接收一个布尔值参数,表示是否深复制。在传入 true 参数时,会进行深复制, 即复制节点及其整个子 DOM 树。
- 如果传入 false,则只会复制调用该方法的节点。
- 当被复制节点改变时,复制节点跟着改变
- 复制返回的节点属 于文档所有,但尚未指定父节点,所以可称为孤儿节点(orphan)。
- 可以通过 appendChild()、 insertBefore()或 replaceChild()方法把孤儿节点添加到文档中。
注意 cloneNode()方法不会复制添加到 DOM 节点的 JavaScript 属性,比如事件处理程 序。这个方法只复制 HTML 属性,以及可选地复制子节点。除此之外则一概不会复制。 IE 在很长时间内会复制事件处理程序,这是一个 bug,所以推荐在复制前先删除事件处 理程序。<ul> <li>item 1</li> <li>item 2</li> <li>item 3</li> </ul> //如果myList保存着对这个<ul>元素的引用,则下列代码展示了使用cloneNode()方法的两种方式: let deepList = myList.cloneNode(true); //深复制,复制ul里面的内容 alert(deepList.childNodes.length); // 3(IE9 之前的版本)或 7(其他浏览器) let shallowList = myList.cloneNode(false); alert(shallowList.childNodes.length); // 0 //浅复制,只复制ul本省,里面的内容不复制
节点操作
// 已知儿子获取父元素 son.parentNode //此处son指任意一个元素 son.parentNode.parentNode //获取爷爷 // 已知父亲获取儿子 parent.children //获取所有子元素,此处parent指任意一个包含子元素的元素 parent.childNodes //获取所有子节点,基本不用 parent.children[0] //第1个子元素 parent.firstElementChild//同上,兼容ie9及以上 parent.children[parent.children.length-1] //最后一个子元素 parent.lastElementChild //同上,兼容ie9及以上 parent.firstChild //第一个子节点,基本不用 parent.lastChild //最后一个子节点,基本不用 // 获取已知元素的上一个及下一个兄弟元素 element.nextElementSibling element.previousElementSibling //删除 父元素.removeChild(子元素) //将父元素中的子元素删除 ele.remove()//自己删除自己,ie不兼容 //克隆 ele.cloneNode()//复制节点本身 ele.cloneNode(true)//复制节点本身及其子节点