饥人谷技术博客

JS中DOM编程总结

2021-04-13  本文已影响0人  茜Akane

Get Started

网页其实是一颗树。

JS如何操作这个树,浏览器往window上加一个document即可。
JS用document操作网页,这就是Document Object Model文档对象模型。
事实:DOM很难用

获取元素,也叫标签(节点包括元素和文本等)

• 有很多API

    window.idxxx或者直接idxxx
    document.getElementByld('idxxx')
    document.getElementsByTagName('div')[0]
    document.getElementsByClassName('red')[0]
    document.querySelector('#idxxx')
    document.querySelectorAll('.red')[0]

• 有s的都得加下标
• 用哪个
工作中用querySelector和querySelectorAll
要兼容IE的才用getElement(s)ByXXX

获取特定元素

• 获取html元素
document.documentElement
• 注意:相当于属性,而不是函数,不用加()
• 获取head元素
document.head
• 获取body元素
document.body
• 获取窗口(窗口不是元素)虽然window不是标签,但是有时候会获取window加一些全局的事件监听
window
• 获取所有元素(将内部的所有标签一字排开)
document.all
这个是个奇葩,第6个falsy值,使用if之后为假。

我们获取到的元素是一个对象,抓取一只div对象看一下

console.dir(div1)看原型链
• ※Chrome显示错了(显示内容.pritotype)
• 自身属性:className、id、style等
• 第一层原型HTMLDivElement.prototype
• 这里面是所有div共有的属性,不用细看
• 第二层原型HTMLElement.prototype
• 这里面是所有HTML标签共有的属性,不用细看
• 第三层原型Element.prototype
• 这里面是多有XML、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和3即可
注意:回车也算一个文本节点。

节点的增删改查

• 创建一个标签节点
let div1 = document.createElement('div')
document.createElement('style')
document.createElement('script')
document.createElement('li')
• 创建一个文本节点
text1= =document.createTextNode('你好')
• 标签里面插入文本
div1.appendChild(text1)(这个是Node提供的接口)
'div1.innerText = '你好'(IE) 或者 div.textContent = '你好''(标准)(这里是element提供的接口)
但是不能用div1.appendChild('你好')
• 插入页面中
创建的标签默认处于JS线程中
你必须把他查到head或者body里面,它才会生效
document.body.appendChild(div)
或者
已在页面中的元素.appendChild(div)
append
• 代码
页面中有div#test1和div#test2

    let div = document.createElement('div')
    test1.appendChild(div)
    test2.appendChild(div) 

• 请问最终div出现在哪里?
答:test2里面
一个元素不能出现在两个地方,除非复制一份。
用cloneNode(let div1 = div.cloneNode())

• 两种方法
旧方法:parentNode.removeChild(childNode)
div.parentNode.removeChild(div)
新方法:childNode.remove()(ie不支持)
div.remove()
• 思考
如果一个node被移出页面(DOM树)
那么它还可以再次回到页面中吗?
答:是可以的,只是移回了内存,还是存在的,将null赋值给div让其与内存断开连接,就会被内存回收掉

• 写标准属性
改class:div.className = 'blue'(全覆盖、class优先判定为关键字)(+=' red'一般不用)
改class:div.classList.add('red')
改style:div.style='width: 100px;color: blue';
改style的一部分:div.style.width='200px'
大小写:div.style.backgroundColor='frank'
改data-*属性:div.dataset.x = 'frank'
• 读标准属性
div.classList/a.href
div.getAttribute('class')/a.getAttribute('href')

image.png
两种方法都可以,但值可能稍微有些不同
改使事件处理函数
• 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)
直接这样就可以了,直接从原来的地方消失

• 查爸爸
node.parentNode或者node.parentElement
• 查爷爷
node.parentNode.parentNode
• 查子代
node.childNodes或者node.children(childNodes如果有空格的话会被当成文本占用长度)(都会实时更新)
注意:若用document.querySelectorAll('li')来获取元素,那么获取的元素长度不变
• 查兄弟姐妹
node.parentNode.childNodes还要排除自己和所有的文本节点
node.parentNode.children还要排除自己
• 查看老大
node.firstChild
• 查看老幺
node.lastChild
• 查看上一个哥哥/姐姐
node.previousSibling(这里面会有文本节点,node.previousElementSibling没有)
• 查看下一个弟弟/妹妹
node.nextSibling
• 遍历一个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))

跨线程操作

插入一个新的标签的完整过程

  1. 在div1放入页面之前,对div1所有的操作都属于JS线程内的操作
  2. 把div1放入页面之时,就会通知渲染线程在页面中渲染div1对应的元素
  3. 把div1放入页面之后,对div1的操作都有可能会触发重新渲染,div1.id = 'newld'可能会重新渲染,也可能不会,div1.title = 'new'可能会重新渲染,也可能不会,如果你连续对div1多次操作,浏览器可能会合并成一次操作,也可能不会(之前在动画里提到过)

属性同步

Property 与 Attribute 的区别

上一篇下一篇

猜你喜欢

热点阅读