本篇文章以介绍常见的DOM节点知识、DOM元素操做方法为目的,其中也对一些比较容易忽略的问题进行简要说明。才疏学浅,若有纰漏之处或建议欢迎留下评论。css
首先,简单看看Node节点。有三个属性我的认为比较须要注意,nodeType、nodeName、nodeValue。html
这个图是来自《Javascript高级程序设计》一书中的Node节点间的关系图谱,比较清晰地介绍了节点之间的关系。node
特别注意上述属性获取的并不仅是元素节点,也会包含文本节点等。因此进行操做时须要进行元素类型判断过滤。
此外,还有一些方式能够得到相关的元素节点。数组
方法 | 简述 | 兼容性 |
---|---|---|
getElementById('id') | 经过id获取 | - |
getElementsByTagName('p') | 经过标签名获取 | - |
getElementsByClassName('class') | 经过class获取 | IE>= 9 |
getElementsByName('name') | 经过name属性获取 | - |
querySelector() | 返回匹配选择器的第一个元素 | IE >= 8 |
querySelectorAll() | 返回匹配选择器的全部元素 | IE >=8 |
特别注意:querySelectorAll()与其余方法获取的DOM元素是不一样的,它返回的是静态的
NodeList 对象,其余返回的是动态的 HTMLCollection 对象。静态意味着不会随着DOM结构的变换而改变。举例以下:浏览器
// html <ul id="list"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> </ul> //js let list = document.getElementById('list'), child1 = document.getElementsByTagName('li'), child2 = document.querySelectorAll('li') console.log(child1.length) // 6 console.log(child2.length) // 6 let ele = document.createElement('li') ele.innerHTML = 7 list.appendChild(ele) console.log(child1.length) // 7 console.log(child2.length) // 6
因此,在使用getElementsByTagName、getElementsByClassName、getElementsByName方法时要特别注意循环处理DOM节点的状况。app
createElement() 建立一个元素节点
createTextNode() 建立一个文本节点
createAttribute() 建立一个属性节点(用setAttribute方法更加方便)
createDocumentFragment() 建立一个文档片断(适合在批量操做DOM元素时使用,详见后面章节的例子)wordpress
元素内容的获取
这里有几个容易混淆的属性,innerHTML、outerHTML、innerText、outerText、textContent,都是能够获取元素内容。区别以下:性能
属性 | 描述 | 兼容性 |
---|---|---|
innerHTML | 返回HTML文本,存在XSS攻击的问题。 | |
outerHTML | 返回内容包含元素及其后代的HTML文本。 | |
textContent | 返回元素全部文本内容,包括隐藏元素的文本,包括<style>、<script>不会返回HTML文本,避免直接设置HTML文本。 | IE9+ |
innerText | 返回文本内容,受CSS样式影响,会触发DOM重排,不包括隐藏元素的文本,不包括<style>、<script>,避免直接设置HTML文本。 | |
outerText | 非标准属性。获取时返回与innerText相同内容,设置时删除当前节点替换为给定文本。 |
元素属性
Element.attributes(): 引用MDN官网的描述spa
返回该元素全部属性节点的一个实时集合。该集合是一个 NamedNodeMap 对象,不是一个数组,因此它没有数组的方法,其包含的属性节点的索引顺序随浏览器不一样而不一样。更确切地说,attributes 是字符串形式的名(name)/值(value)对,每一对名/值对对应一个属性节点。设计
ele.getAttribute(attributeName) 获取属性
ele.setAttribute(name, value) 设置属性
HTMLElement.dataset: 获取data-*属性集
元素样式
HTMLElement.style 返回元素的内联样式(没错,样式表的属性会被忽略)
单个样式的设置:ele.style.color='#000'
多个样式的设置:
ele.style.cssText='color: blue'
ele.setAttribute('style', 'color: blue')
获取元素样式信息:
window.getComputedStyle(ele).color
window.getComputedStyle(ele).getPropertyValue('color')
'::after'
。关于getComputedStyle详细介绍能够看看张鑫旭大神的获取元素CSS值之getComputedStyle方法一文。方法 | 简述 |
---|---|
node.appendChild(newNode) | 向node节点插入一个新节点newNode |
node.insertBefore(newNode, tarNode) | 在node节点的tarNode子节点前插入一个新节点newNode |
node.replaceChild(newNode, tarNode) | 替换node节点的tarNode子节点为新节点newNode |
node.removeChild(tarNode) | 移除node节点的tarNode子节点 |
node.cloneNode(flag) | 复制节点,flag: true 深复制;flag: false 浅复制 |
此处深复制为复制节点及其整个子树,浅复制则仅复制节点自己。
频繁进行DOM操做其实会形成屡次重排Reflow,影响性能。举个常见的例子,在id为container的元素中添加5个按钮,每一个按钮的文案是相应序号,点击打印输出对应序号。解决办法有如下几种:
依次建立button元素,使用appenChild添加到列表中
固然,这个方法是最不推荐的,由于屡次对DOM进行操做,会形成屡次页面重排,性能太差。
let container = document.getElementById('container') for(let i = 1; i <= 5; i++) { let btn = document.createElement('button'), text = document.createTextNode(i) btn.appendChild(text) btn.addEventListener('click', () => { console.log(i) }) container.appendChild(btn) }
利用DocumentFragment
引用MDN官网关于DocumentFragment的介绍:
DocumentFragment 接口表示一个没有父级文件的最小文档对象。它被当作一个轻量版本的 Document 使用,用于存储已排好版的或还没有打理好格式的XML片断。最大的区别是由于DocumentFragment不是真实DOM树的其中一部分,它的变化不会引发DOM树的从新渲染的操做(reflow) ,或者致使性能影响的问题出现。
没错,利用DocumentFragment咱们可以避免方法1中屡次操做DOM的问题,性能获得提高。
let container = document.getElementById('container'), fragment = document.createDocumentFragment() for(let i = 1; i <= 5; i++) { let btn = document.createElement('button'), text = document.createTextNode(i) btn.appendChild(text) btn.addEventListener('click', () => { console.log(i) }) fragment.appendChild(btn) } container.appendChild(fragment)
利用字符串拼接
使用字符串拼接的方法插入DOM元素是效率最高的。而且,这里将事件绑定到了父元素上,一方面可使用动态添加元素的事件,另外一方面当须要在大量元素上绑定事件时,这种方法更加优雅而且节省内存。
let container = document.getElementById('container'), btns = ''; for(let i = 1; i <= 5; i++) { let btn = `<button class="btn_num">${i}</button>` btns += btn } container.addEventListener('click', (event) => { let target = event.target if(target.className == 'btn_num') { console.log(target.innerHTML) } }) container.innerHTML = btns