简单总结DOM基础操作

1,099 阅读4分钟

什么是DOM?

我们每天使用的网页其实是一棵树 image.png 用JS如何操作这棵树?
浏览器往window上加上一个document
之后,JS用document就可以对网页实现操作
这就是DOM(Document Object Model),又称文档对象模型

然而,我们得知道一个事实:DOM很难用,它的很多操作十分反人类

获取元素(标签)

  1. window.idxxx 或 直接 idxxx
  2. document.getElementById('idxxx')
  3. document.getElementsByTagName('div')[0]
    • 最后的数字用来选择操作页面中第几个div
  4. document.getElementsByClassName('red')[0]
  5. document.querySelector('#idxxx')
  6. 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执行下面语句
    • image.png
    • 可以看出它是一个falsy值

显然,获取到的元素都是一个对象,我们需要搞清楚它的原型

元素的六层原型链

我们抓一只野生的div对象来看看

image.png 将它的原型链逐一展开,能得到它共有六层原型链

image.png

如图可看出,在元素之上,还拥有一个节点属性

什么是节点(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会出现在哪?

  1. test1
  2. test2
  3. 都在 答案是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.href
  • div.getAttribute('class')/a.getAttribute('href')
  • 两种方法都行,但值可能会稍微不同

改事件处理函数

div.onclick

  • 默认为null
  • 默认点击div不会有任何事情发生
  • 但如果把div.onclick改为一个函数fn
  • 那么点击div时,浏览器就会调用这个函数
  • 并且是这样调用的fn.call(div,event)
  • div会被当做this
  • event包含了点击事件的所有信息

image.png

改内容

改文本内容

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))

这其实就是运用了遍历一棵树的算法