目录
DOM概览
DOM获取元素
DOM获取到的元素的原型
DOM元素的增删改查
DOM操作跨线程原理
一、DOM概览
网页其实是一棵树
-
JS如何操作这棵树
-
浏览器往
window上加一个document即可 -
JS用
document操作网页 -
这就是Document Object Model 文档对象模型 简称:DOM
-
学习了DOM后,体会到的一个道理
- DOM很难用,我一定要封装DOM
二、获取元素
1.获取元素
-
可以通过很多API获取元素
-
window.idxxx或直接idxxx如果id和全局属性冲突 这个方法就不能用 -
document.getElementById('idxxx') -
document.getElementsByTagName('div')[0]找到所有div标签,可以输入下标确定具体哪一个 -
document.getElementsByClassName('red')[0]找到所有类名为red的标签 -
document.queryselector('#idxxx')要加#号 -
document.queryselectorAll('.red')[0]
-
-
如果不考虑兼容性就用
document.queryselector和document.queryselectorAll -
如果考虑兼容IE就只能用
getElement(s)Byxxx
2. 获取特定元素
-
获取html标签
document.documentElement -
获取head元素
document.head -
获取body元素
document.body -
获取窗口(窗口并不是一个元素)
window -
获取所有元素
-
document.all这是IE发明的属性 但所有浏览器都能用 -
这个
document.all是第六个falsy值
-
三、DOM获取到的元素的原型
-
DOM获取到的元素其实是对象,这里要搞清楚它的原型,这个很重要
-
console.dir(div)查看获取到的div的原型链-
chrome显示的原型的名字可能有些问题 -
自身属性:
className、id、style等等属性 -
第一层原型
HTMLDivElement.Prototype里面是所有div的共有属性,不用特别细看 -
第二层原型
HTMLElement.prototype里面是HTML标签的共有属性,不用特别细看 -
第三层原型
Element.prototype里面是所有XML、HTML的共有属性,因为浏览器不止可以显示HTML,还有其他类型也能显示 -
第四层原型
Node.prototype里面是所有节点的共有属性,包括XML、HTML标签文本注释等属性 -
第五层原型
EventTarget.prototype里面最重要的函数属性addEventListener后面详细学习 -
最后一层原型
Object.prototype根对象
-
节点Node 包括
-
MDN有完整描述,
x.nodeType得到一个数字-
1表示元素Element也叫元素标签Tag -
3表示文本Text -
8表示注释comment -
9表示文档Document -
11表示文档片段DocumentFragment -
重点记住1和2是什么
-
四、元素的增删改查
1. 增
创建一个节点
-
let div1 = document.createElement('div') -
document.createElement('style') -
document.createElement('script') -
document.createElement('li')
创建一个文本节点
text1 = document.createTextNode('你好')
标签里面插入文本
-
div1.appendChild(text1) -
div1.innerText = '你好'或者div1.textContent = '你好' -
但是不能用
div1.appendChild('你好')
插入到页面中
-
创建的标签默认处于JS线程中
-
必须把它插入到head或者body里,它才会在页面中生效
-
document.body.appendchild(div) -
或者
已在页面中的元素.appendChild(div)
appendchild解析
- 代码
//页面中有div#test1和div#test2
let div = document.createElment('div')
test1.appendchild('div')
test2.appendchild('div2')
- 最终这个div只会出现在
test2里,因为一个元素不能出现在两个地方,除非复制一份
复制节点
-
let div2 = div.cloneNode() -
如果括号为空 那么默认是浅拷贝,如果括号内为
true那就是深拷贝
2. 删
方法1 (旧)
parentNode.childChild(childNode)
方法2 (新)
childNode.remove() 不兼容IE
注意
- 如果一个Node被移出页面(DOM树),是可以被恢复到页面中的,因为这个Node在内存里还存在,除非把内存对应的Node也移除就彻底回不来了
3.改
写标准属性
-
改
class:div.className = 'rad blue'这个方法会把该Node的所有class全部覆盖掉 -
改
class:div.classList.add('rad') -
改
style:div.style = 'width: 100px; color:blue' -
改
style的一部分:div.style.width = '200px' -
注意区分大小写:
div.style.backgroundColor = 'skybule' -
改
data-*属性:div.dataset.x = 'jack'
读标准属性
div.classList/a.href 这样读属性可能会有问题
div.getAttribute('class')/a.getAttribute('href') 这种方法最稳妥
改事件处理函数
-
div.onclick默认为null-
默认点击
div不会有任何事情发生 -
但是如果把
div.onclick改为一个函数fn -
那么点击
div的时候,浏览器就会调用这个函数 -
调用方式是
fn.call(div,event)div被当做this -
event则包含了点击事件的所有信息,如坐标等 -
div.addEventListener后面详细学习,是div.onclick的升级版
-
改文本内容
-
div.innerText = 'xxx' -
div.textContent = xxx -
两者几乎没有区别
改HTML内容
div.innerHTML = '<strong>重要内容</strong>'
改标签
-
div.innerHTML = ''先清空 -
div.appendchild(div2)再加内容
改父级元素
-
找一个新爹
-
newParent.appendchild(div) -
直接这样,会让想改的元素在原来的地方消失
-
4.查
查父级元素
node.parentNode或node.parentElement
查父级元素的父级元素
node.parentNode.parentNode
查子代元素
Node.children或node.childNodes用第一种居多,两种都会实时更新
查兄弟姐妹元素
-
node.parentNode.childNodes -
node.parentNode.childen用这种就可以不用再排除文本节点,方便省事 -
两种方法在选中父级元素后都要排除掉自己(egg 疼)
查第一个子代
node.firschild
查最后一个子代
node.lastchild
查上下一个兄弟元素
-
node.previousSibling上一个元素 -
node.nextSibling下一个元素 -
如果只想查看元素就在
Sibling前加Element
遍历一个div里的所有元素
- 代码如下
travel = (node,fn) => {
fn(node)
if(node.children){
for(let i = 0; i<node.children.length; i++){
travel(node.children[i],fn)
}
}
}
travel(div1,(node) => console.log(node))
五、DOM操作跨线程原理
-
概念: DON操作是跨线程操作
-
浏览器分为渲染引擎和JS引擎等
跨线程操作
-
各线程各司其职
-
JS引擎不能操作页面,只能操作JS
-
渲染引擎不能操作JS,只能操作页面
-
document.body.appendchild(div1) -
这个JS代码是如何改变页面的
-
-
跨线程通信
-
当浏览器发现JS在
body里加了一个div1对象 -
浏览器会通知渲染引擎在页面里也新增一个
div元素 -
新增的
div元素所有属性照抄div1对象的属性
-
插入新标签的完整过程
-
在
div1放入页面之前- 我们对
div1所有的操作都属于JS线程内的操作,是不会直接影响到页面的
- 我们对
-
把
div1放入页面时-
浏览器发现了JS的意图
-
浏览器通知渲染线程在页面中渲染
div1对应的元素
-
-
把
div1放入页面之后-
对
div1的操作都有可能会触发重新渲染 -
div1.id = 'newId'可能会重新渲染也可能不会,这取决于div1的id有没有让浏览器渲染的属性 -
div1.title = 'new'可能会重新渲染也可能不会,理由同上 -
如果对
div1连续进行多次操作,浏览器可能会合并成一次操作,也可能不会,假如在多次操作的中间,没有改变要求浏览器进行渲染的属性,就会合并成一次操作
-
属性同步
-
标准属性和
data-*属性-
对div1的标准属性和
data-*属性进行修改,会被浏览器同步到页面中 -
比如
id/className/title等
-
-
非标准属性
-
对非标准属性的修改,只会停留在JS线程中,不会被同步到页面里
-
比如
x属性(给标签新建一个x属性,修改x属性就不会被同步到页面里)
-
-
启示
- 如果有自定义属性想被同步到页面中,可以用
data-作为前缀
- 如果有自定义属性想被同步到页面中,可以用
Property和Attribute
-
Property属性- JS线程中
div1的所有属性,叫做div1的property
- JS线程中
-
Attribute也是属性- 渲染引擎中div1对应标签的属性,叫做
Attribute
- 渲染引擎中div1对应标签的属性,叫做
-
区别
-
大部分时候,同名的
Property和Attribute的值相等 -
但如果不是标准属性,那他们只在一开始时相等
-
Attribute只支持字符串,Property支持字符串、布尔等类型
-