1. DOM(Document Object Model)文档对象模型
JavaScript中,将网页视为树结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<p>文字1</p>
<span>文字2</span>
</div>
<p>
<span>文字3</span>
文字4
</p>
</body>
</html>
JavaScript是通过document操作“这棵树”,document是浏览器加上的对象
2. 获取元素的方式
-
window.idName或者直接用idName
-
document.getElementById('a') 获取ID为a的元素,只返回一个
-
document.getElementsByName('a') 获取所有name属性值为a的元素,返回一个在 (X)HTML document的节点列表集合
-
document.getElementsByTagName('p') 返回一个包括所有给定标签名称的元素的HTML集合
HTMLCollection。 整个文件结构都会被搜索,包括根节点。返回的HTML集合是动态的, 意味着它可以自动更新自己来保持和 DOM 树的同步而不用再次调用document.getElementsByTagName() -
document.getElementsByClassName('a') 返回一个包含了所有指定类名的子元素的类数组对象。当在document对象上调用时,会搜索整个DOM文档,包含根节点。你也可以在任意元素上调用
getElementsByClassName()方法,它将返回的是以当前元素为根节点,所有指定类名的子元素。 -
document.querySelector(selector) 返回文档中与指定选择器或选择器组匹配的第一个 Element对象。 如果找不到匹配项,则返回
null -
document.querySelectorAll 返回与指定的选择器组匹配的文档中的元素列表 (使用深度优先的先序遍历文档的节点)。返回的对象是
NodeList获取特定的元素
-
document.documentElement 获取html元素
-
document.head 获取head元素
-
document.body 获取body元素
-
window 获取窗口(实质不是元素)
-
document.all 获取所有元素(直接判断document.all是false,但是能获取到所有元素)
注意:falsy 新晋成员 document.all (undefined/null/NaN/''/0)
3. 元素原型
以div为例,在chrome中查看一下它的原型
console.dir(div)
具体的链路是:HTMLDivElement---HTMLElement---Element---Node---EventTarget---Function---Object
然后不同的原型上加了各自的一些方法,其中部分方法的功能是一致的,所以在一些DOM操作中,一个动作对应多种写法。
4. 节点(node)和元素(element)区别
console.log(node.nodeType) 查看节点类型
元素是节点的一个子类型
| 常见类型 | 值 | 描述 |
|---|---|---|
| 元素节点 | 1 | 一个元素 节点,例如 。 |
| 文本节点 | 3 | Element 或者 Attr中实际的 文字 |
| 注释 | 8 | 一个 Comment 节点。 |
| 文档 | 9 | 一个 Document 节点。 |
5. 节点的增删改查
- 创建一个标签节点
createElement
let box = document.createElement('div')
- 创建一个文本节点
createTextNode
let text1 = document.createTextNode('你好')
- 标签里面插入文本
appendChildinnerTexttextContent
box.appendChild(text1)
box.innerText = '你好'
box.textContent('你好')
注意:在JavaScript中通过createElement创建标签,默认是存在于JavaScript线程中,需要通过document.appendChild插入到head或body中才能生效
假设页面中有div#test1和div#test2
let div = documet.createElement('div')
test1.appendChild(div)
test2.appendChild(div)
这个新建的div元素,最终会被插入到#test2上
- 删除节点
子节点.parentNode.removeChild(子节点)
子节点.remove()(IE不支持)
注意:删除只是从DOM树中删除,内存中还是有的,所以可以重新添加,删除后,将子节点置为null,就可以完全删除
-
修改标准属性
div.className = 'red'不能用保留字作为key,所以.class不行,要用.className
将div对应的标签的类改为red,如果之前有其他类,会被删除
div.classList.add('red') //div对应标签增加一个red类,不影响之前已有的类 div.style.backgroundColor = 'red' div.style['background-color'] = 'red' div.dataset.x = 'xxx' //修改自定义的data-x属性 -
读取标准属性
div.classList/a.href div.getAttribute('class')/a.getAttribute('href')<a id='test' href='/xxx' >test.href的值可能是 域名+/xxx稳妥起见,用test.getAttribute('href')获取
-
修改文本内容
div.innerText = 'hello' div.textContent = 'hello' -
修改HTML内容
div.innerHTML = '<p>hello world<p>' -
修改标签
div.innerHTML = '' //先清空 div.appendChild(div1) //再加内容 -
修改父节点
<div id="a"> <p>11111</p> </div> <div id="b"></div>let p = document.querySelector('p') b.appendChild(p) //p从a转到了b上
-
查父节点 node.parentNode / node.parentElement
-
查子元素 node.childNodes / node.children
-
查兄弟元素 node.parentNode.children 再排除自己
-
上一个兄弟元素 node.previousSibling
-
下一个兄弟元素 node.nextSibling
-
遍历一个div里的所有元素 (递归)
let div = document.querySelector('div'); function findAllChildren(ele, fn) { fn(ele) if (ele.children.length !== 0) { for (let i = 0; i < ele.children.length; i++) { findAllChildren(ele.children[i], fn) } } } findAllChildren(div, (ele) => { console.log(ele) }) -
改写事件处理函数
以
div.onclick为例,默认的onclick事件是空,当定义事件操作后,点击div时,浏览器会调用此函数,fn.call(div,event),this指向当前div,event则包含了点击事件的所有信息
6. DOM操作-跨线程
JS引擎操作JS,渲染引擎操作页面
当JS引擎执行到document.body.appendChild(div)时,浏览器就会通知渲染引擎在页面新增一个div元素,并同步属性
插入新标签的大致过程
-
在div放入(appendChild)页面之前,都属于JS线程内的操作
-
将div放入页面时,浏览器会通知渲染进程,进行渲染
-
在div放入页面后,对div的所有操作都有可能会触发重新渲染
属性同步
-
标准属性
通过JS修改标签的标准属性,例如,id、class、title等,会被浏览器自动同步到页面,显示的没变,当再次获取或者输出时,会变
-
data-x 自定义属性,通过node.dataset 修改的自定义属性,也会被浏览器同步到页面
-
非标准属性,修改后不同被同步,所以自定义属性建议使用data-为前缀
拓展阅读: