DOM编程
JS 用 document 操作网页,这就是Document Object Model 文档对象模型
获取元素/标签
- API
window.id
或者直接id
返回一个匹配特定 ID的元素,如果id命名与一些特殊名词不冲突可以使用document.getElementById('id')
返回一个匹配特定 ID的元素,如果id命名与一些特殊名词冲突使用该方法,比如id名为parentDocument.getElementsByTagName()
返回一个包括所有给定标签名称的元素的HTML集合- 比如
document.getElementsByTagName('div')[0]
返回所有div元素,[0]表示返回第一个div元素
- 比如
Document.getElementsByClassName()
返回一个包含了所有指定类名的子元素的类数组对象document.getElementsByClassName('red')[0]
document.querySelector('#id')
返回文档中与指定选择器或选择器组匹配的第一个 Element对象。 如果找不到匹配项,则返回nulldocument.querySelectorAll('.red')[0]
返回与指定的选择器组匹配的文档中的元素列表,返回的对象是 NodeList , [0]表示返回第一个元素
获取特定元素
document.documentElement
获取 html 元素document.head
获取 head 元素document.body
获取 body 元素window
获取窗口(窗口不是元素)document.all
获取所有元素
用来证明是不是IE浏览器,if(document.all)
在IE浏览器中为真,在其他浏览器中为假
div原型链
节点的更删改查
增
- 创建一个标签节点
let div = document.createElement('div')
document.createElement('style')
document.createElement('script')
- 创建一个文本节点
text = document.createTextNode('你好')
- 在标签里插入文本
div.appendChild(text)
div.innerText = '你好'
div.textContent = '你好'
p
- 插入到页面中
上述创建的标签默认处在 JS 线程中,需要插入到head或者body里面才会生效document.body.appendChild(div)
.appendChild(div)
已在页面中的元素
- appendChild
// 假设页面中有两个div,一个命名为test1,一个命名为test2
let div = document.createElement('div')
test1.appendChild(div)
test2.appendChild(div)
// 最终div会在test2里
// 一个元素不能出现在两个地方,除非复制
删
- 方法一(旧方法)
parentNode.childChild(childNode)
div.parentNode
div.parentNode.removeChild(div)
- 方法二(新方法)
childNode.remove()
改
改属性
- 写标准属性
- 改class:
div.className = 'red'
(修改后的会覆盖之前的)div.classList.add('blue')
(会在原来的基础上增加)
- 改style:
div.style = 'color:blue;'
(修改后的会覆盖之前的)div.style.color = 'blue'
(只改颜色部分)
- JS不支持比如
background-color
这种带-的,所以用大写表示,如下div.style.backgroundColor = 'black'
- 改 data- 属性:
div.dataset.x = 'x'
- 改class:
- 读标准属性
- 直接读属性
div.id
div.style
a.href
- 通过获取属性
div.getAttribute('style')
a.getAttribute('href')
- 对于a标签来说,两种方法的值可能不同
- 直接读属性
改事件处理函数
div.onclick
默认为 null- 默认点击 div 不会发生任何事,如果把
div.onclick
改为一个函数fn,那么点击 div 的时候,浏览器就会调用这个函数 - 调用时为
fn.call(div,event)
- div 会被当作this,event包含了点击事件的所有信息
- 默认点击 div 不会发生任何事,如果把
div.addEventListener
是div.onclick
的升级版
改内容
- 改文本内容 (下面两种方法效果相同)
div.innerText = 'xxx'
div.textContent = 'xxx'
- 改 HTML 内容
div.innerHTML = '<p>hi</p>'
- 改标签
div.innerHTML = ''
先清空div.appendChild(div2)
再加内容
改父元素
newParent.appendChild(div)
查
- 查父元素
node.parentNode
或node.parentElement
- 查父元素的父元素
node.parentNode.parentNode
- 查子代
node.childNodes
该方法查子代,会将文本节点(比如回车空格)算进长度里node.children
该方法查子代,长度里只有子代节点,优先使用该方法
- 查兄弟姐妹
node.parentNode.childNodes
不仅需要排除自己,还需要排除文本节点node.parentNode.children
需要排除自己,使用遍历将自己排除
- 查看第一个子代
node.firstChild
- 查看最后一个子代
node.lastChild
- 查看上一个哥哥/姐姐
node.previousSibling
可能会查到文本节点node.previousElementSibling
查上一个临近的元素
- 查看下一个弟弟/妹妹
node.nextSibling
node.nextElementSibling
- 遍历一个div里的所有元素
travel = (node,fn) => {
fn(node)
if(node.children){
for(let i = 0; i<node.children.length; i++){
travel(node.children[i],fn)
}
}
}
travel(div,(node) => console.log(node))
DOM操作跨线程
浏览器功能划分为渲染引擎和JS引擎
跨线程操作
- 各线程各司其职
- JS引擎不能操作页面,只能操作JS
- 渲染引擎不能操作JS,只能操作页面
- 跨线程通信
- 当浏览器发现JS在body里加了一个div1对象
document.body.appendChild(div1)
- 浏览器会通知渲染引擎在页面里也新增一个div元素
- 当浏览器发现JS在body里加了一个div1对象
插入新标签的过程
- 在div1放入页面之前
- 对div1所有的操作都属于JS线程内的操作
- 把div1放入页面之时
- 浏览器会发现JS的意图
- 随后通知 渲染线程在页面中渲染div1对于的元素
- div1放入页面之后
- 对div1的操作都有可能会触发重新渲染
- 如果连续对div1多次操作,浏览器可能会合并成一次操作,也可能不会
属性同步
- 标准属性
- 对div1的标准属性的修改,会被浏览器同步到页面种,比如
id
,className
,title
等等
- 对div1的标准属性的修改,会被浏览器同步到页面种,比如
- data-* 属性 同上
- 非标准属性
- 对非标准属性的修改,只会停留在JS线程中,不会同步到页面里,比如
x
属性
- 对非标准属性的修改,只会停留在JS线程中,不会同步到页面里,比如
- 如果有自定义属性想要同步到页面中,就使用data-作前缀
Property 与 Attribute
- property属性
- JS线程中div1的所有属性,叫作div1的property
- attribute属性
- 渲染引擎中div1对应标签的属性,叫作attribute
- 二者区别
- 大部分时候,同名的property和attribute值相等
- 如果不少标准属性,二者的值会在一开始相等
- attribute只支持字符串
- property支持字符串、布尔等类型