什么是DOM?
我们每天使用的网页其实是一棵树
用JS如何操作这棵树?
浏览器往window上加上一个document
之后,JS用document就可以对网页实现操作
这就是DOM(Document Object Model),又称文档对象模型
然而,我们得知道一个事实:DOM很难用,它的很多操作十分反人类
获取元素(标签)
window.idxxx或 直接idxxxdocument.getElementById('idxxx')document.getElementsByTagName('div')[0]- 最后的数字用来选择操作页面中第几个div
document.getElementsByClassName('red')[0]document.querySelector('#idxxx')document.querySelectorAll('.red')[0]
一般用5和6,要兼用IE时才用2,3,4
获取特定元素
document.documentElement获取html元素document.head获取head元素document.body获取body元素window获取窗口(窗口不是元素)document.all获取所有元素- 这个document.all是一个falsy值
- 只有在IE中它才是真
- 用Chrome执行下面语句
- 可以看出它是一个falsy值
显然,获取到的元素都是一个对象,我们需要搞清楚它的原型
元素的六层原型链
我们抓一只野生的div对象来看看
将它的原型链逐一展开,能得到它共有六层原型链
如图可看出,在元素之上,还拥有一个节点属性
什么是节点(Node)?
MDN有完整描述->Node_MDN
DOM 的最小组成单位叫做节点(node)。文档的树形结构(DOM 树),就是由各种不同类型的节点组成,用x.nodeType可以得到一个数字:
- 1:元素Element(也叫标签Tag)
- 3:文本Text
- 8:注释Comment
- 9:文档Document
- 11:文档片段DocumentFragment
节点的增删改查
增
let div1 = document.createElement('div') //创建一个标签节点
text1 = document.createTextNode('你好') //创建一个文本节点
div1.appendChild(text1) //在标签里插入文本
从上述操作可以看出,要在标签里插入文本需要三句代码,十分反人类 所以有更简单的方法:
div1.innerText='你好'
div1.textContent='你好'
// 但是不能用 div1.appendChild('你好')
这样创建完div后,它只是处于JS线程中,并不会显示在页面上,所以还需把它插入页面
document.body.appendChild(div1)
假设,页面中有div#test1和div#test2
let div = document.createElement('div')
test1.appendChild(div)
test2.appendChild(div)
最后div会出现在哪?
- test1
- test2
- 都在 答案是2,一个元素不能出现在两个地方,除非复制一份
删
parentNode.childChild(childNode) //旧方法
childNode.remove() //新方法
这样的删除方法只是将节点从树里删掉,它还保留在内存里
如何彻底删除?
在执行完上面的代码之后,加上childNode = null
改
改标准属性
- 改class:
div.className = 'red blue'(全覆盖) - 改class:
div.classList.add('red')增加一个class名,不会覆盖之前 - 改style:
div.style = 'width: 100px; color: blue;'(旧样式全覆盖) - 改style一部分:
div.style.width: '200px' - 改data-*属性:
div.dataset.x = 'abc'- 现在几乎没什么人用,使用它是因为之前的某一个特定时期,我们需要在每一个元素上面加一些自定义的属性
读标准属性
div.classList/a.hrefdiv.getAttribute('class')/a.getAttribute('href')- 两种方法都行,但值可能会稍微不同
改事件处理函数
div.onclick
- 默认为null
- 默认点击div不会有任何事情发生
- 但如果把div.onclick改为一个函数fn
- 那么点击div时,浏览器就会调用这个函数
- 并且是这样调用的
fn.call(div,event) - div会被当做this
- event包含了点击事件的所有信息
改内容
改文本内容
div1.innerText='xxx'
div1.textContent='xxx'
改HTML内容
div1.innerHTML='<strong>重要内容</strong>'
改标签
div1.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.nextSibling查看看一个弟弟/妹妹
举一个奇葩的例子: 构建一个列表
<ul id = "test">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
我们想知道test.childNodes的长度是多少?
console.log(test.childNodes.length)
打印出内容是 7,因为它会把回车+空格(缩成一个空格),算作一个长度
那如果我们想得到一个正常一点的答案应该怎么写?
console.log(test.children.length)
这样打印出的内容就是 3
遍历一个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))
这其实就是运用了遍历一棵树的算法