js中dom节点操作

——基础不牢,地动山摇。本文来巩固一些原生的dom操作,在此之前先明确一下html的构成。

html 组成

html整个文档是由节点(Node)组成的,那么节点(Node)到底是什么呢,看mdn给出的定义。

Node

Node 是一个接口,各种类型的 DOM API 对象会从这个接口继承。它允许我们使用相似的方式对待这些不同类型的对象;比如,继承同一组方法,或者用同样的方式测试。

大概有这11种类型

常量描述
Node.ELEMENT_NODE1一个 元素 节点,例如 <p><div>
Node.ATTRIBUTE_NODE2元素 的耦合 属性
Node.TEXT_NODE3Element 或者 Attr 中实际的 文字
Node.CDATA_SECTION_NODE4一个 CDATASection,例如 <!CDATA[[ … ]]>
Node.PROCESSING_INSTRUCTION_NODE7一个用于 XML 文档的 ProcessingInstruction (en-US) ,例如 <?xml-stylesheet ... ?> 声明。
Node.COMMENT_NODE8一个 Comment 节点。
Node.DOCUMENT_NODE9一个 Document 节点。
Node.DOCUMENT_TYPE_NODE10描述文档类型的 DocumentType 节点。例如 <!DOCTYPE html> 就是用于 HTML5 的。
Node.DOCUMENT_FRAGMENT_NODE11一个 DocumentFragment 节点
 <ul class="ul" id="ul"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>//对于这样一个html片段来说。如果利用Node.childNodes,获取到的结果如下有五个li,和六个空文本节点组成 

所以我们的html 基本都是由这些node节点组成。主要有element元素节点(nodeType为1),文本节点(nodeType为3),注释等等(nodeType为8)。我们详细看一下element元素节点

element元素节点

Element 是一个通用性非常强的基类

*所有属性继承自它的祖先接口 Node,并且扩展了 Node 的父接口 EventTarget

通俗来说就是div,ul,li 这些标签就叫元素节点(element),我们通常所说的操作dom,节点大多数就是在此类上,调用对应的方法。根据mdn文档中所述,element继承自node的(element本身是就是node的一种类型)。

那么我们继续追根溯源,Node从其父类型 EventTarget[1] 继承属性.

EventTarget 接口由可以接收事件、并且可以创建侦听器的对象实现。换句话说,任何事件目标都会实现与该接口有关的这三个方法。

简单来说EventTarget提供了时间监听器addEventListener等三个方法处理事件,这就解释了所有的element元素都可以调用addEventListener方法。

Node 与 Element 关系

到此我们捋一下他们之间的关系

做完这些铺垫,可以正式进入操作dom了。更多其他的操作可以直接去mdn找Element实例对应的方法。

增加

1.Node.appendChild()

该方法将一个节点附加到指定父节点的子节点列表的末尾处。如果将被插入的节点已经存在于当前文档的文档树中,那么 appendChild() 只会将它从原先的位置移动到新的位置(不需要事先移除要移动的节点)。

2.Element.append()

该方法在 Element的最后一个子节点之后插入一组 Node 对象或 DOMString 对象(就是字符串)。被插入的 DOMString 对象等价为 Text 节点。

与 Node.appendChild() 的差异:

  • Element.append()允许追加 DOMString 对象,而 Node.appendChild() 只接受 Node 对象。
  • Element.append() 没有返回值,而 Node.appendChild() 返回追加的 Node 对象。
  • Element.append() 可以追加多个节点和字符串,而 Node.appendChild() 只能追加一个节点。

主要就是插入节点数量的多少,还有就是二者一个定义在node类中,一个定义在element类中。

3.Node.insertBefore()

该方法在参考节点之前插入一个拥有指定父节点的子节点。如果给定的子节点是对文档中现有节点的引用,insertBefore() 会将其从当前位置移动到新位置(在将节点附加到其他节点之前,不需要从其父节点删除该节点)

1.appendChild<ul class="ul" id="ul"><li>1</li><li>2</li><li>3</li><li>4</li><!-- <li>5</li> --></ul> let li = document.createElement('li'); li.innerHTML = 5 let ul = document.querySelector('ul'); ul.appendChild(li)   
2.append let li1 = document.createElement('li'); let li2 = document.createElement('li') li1.innerHTML = 5 li2.innerHTML = 6 let ul = document.querySelector('ul'); ul.append(li1,li2)
3.insetBefore  let li = document.createElement('li'); li.innerHTML = 0 let ul = document.querySelector('ul'); let li1 = ul.firstChild; ul.insertBefore(li,li1) 

删除

1.Element.remove()

该方法,把对象从它所属的 DOM 树中删除。

2.Node.removeChild()

该方法从 DOM 中删除一个子节点。返回删除的节点。

注意

  • child 是要移除的那个子节点。
  • nodechild的父节点。
  • oldChild 保存对删除的子节点的引用。oldChild === child. 如果保存了引用js垃圾回收将不会清理内存

用法

 //删除第一个li<ul class="ul" id="ul"><li>1</li><li>2</li><li>3</li><li>4</li><!-- <li>5</li> --></ul> 1.remove let ul = document.querySelector('ul'); let li1 = ul.firstElementChild; li1.remove() 2.removeChild()let ul = document.querySelector('ul');let li1 = ul.firstElementChild;ul.removeChild(li1) 

结果如下

修改

1.Node.replaceChild()

该方法用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点。

2.Element.replaceChildren()

该方法将一个 Node的后代替换为指定的后代集合。这些新的后代可以为 DOMStringNode 对象。

Element.replaceChildren(...nodesOrDOMStrings) // 返回 undefined
parentNode.replaceChild(newChild, oldChild); 

查找

如果要找某个具体节点直接利用document.querySelector(),去选择就好。这里只提供寻找父子节点。

1.Node.parentNode

该属性返回指定的节点在 DOM 树中的父节点。

parentNode 是指定节点的父节点。一个元素节点的父节点可能是一个元素 (Element) 节点,也可能是一个文档 (Document) 节点,或者是个文档碎片 (DocumentFragment) 节点。

2.Node.parentElement

该属性返回指定的节点在 DOM 树中的父元素节点。

1.Element.children

是一个只读属性,返回 一个 Node 的子elements,是一个动态更新的 HTMLCollection(一个可迭代的对象)。

2.Node.childNodes

返回包含指定节点的子节点(Node)的集合,该集合为即时更新的集合(live collection)。

测试小例子

🌰1 翻转内部节点

 <ul class="ul" id="ul"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul> 

将内部节点翻转。

思路1.获取内部节点,翻转之后放回去。

 let div = document.querySelector('div'); let child = [...ul.children]; //这里返回的是类数组,需要拓展一下。 for(let i = 0,j=child.length-1;i<j;i++,j--){ [child[i],child[j]] = [child[j],child[i]] } ul.replaceChildren(...child) 

思路2.利用appendChild的特性去修改,如果添加的是本身的元素就会将该元素移动到最后面。

 let div = document.querySelector('div'); let child = [...ul.children]; for(let i =child.length-1;i>=0;i--){ul.appendChild(child[i]) } 

结果

🌰2 遍历element节点

<div id="content"> <div id="level-1.1"><div id="level-2.1"><div id="level-3.1"></div></div> </div> <div id="level-1.2"><div id="level-2.2"><div id="level-3.2"></div></div> </div> <div id="level-1.3"><div id="level-2.3"></div> </div> 
</div>
//我们把读取到ID作为遍历到该节点。 

思路1.dfs深度优先,递归实现

let entry = document.querySelector('#content'); const dfs=(input)=>{ console.log('dfs,start')let id= input.idconsole.log(id)let children = [...input.children];if(children.length == 0){return }for(let i= 0;i<children.length;i++){dfs(children[i])}console.log('dfs,end') }
 dfs(entry) 

思路2.bfs广度优先,采用辅助队列实现

 let entry = document.querySelector('#content');const bfs = (input)=>{ console.log('bfs,start')let id = input.id;let queue = [input];while(queue.length){let element = queue.shift();console.log(element.id);let children = [...element.children];for(let i = 0;i<children.length;i++){ queue.push(children[i])}}console.log('bfs,end') }bfs(entry) 

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值