JS中DOM编程总结

作者: 茜Akane | 来源:发表于2021-04-13 00:35 被阅读0次

    Get Started

    • 网页结构
    • 节点的增删改查
    • 跨线程操作
    • 属性同步
    • Property 与 Attribute 的区别

    网页其实是一颗树。

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

    跨线程操作

    • 各线程各司其职
      JS引擎不能操作页面,只能操作JS。渲染引擎不能操作JS,只能操作页面。
    • 跨线程通信
      当浏览器发现JS在body里面加了个div1对象,浏览器就会通知渲染引擎在页面里也新增一个div元素,新增的div元素所有属性都照抄div1对象。
      在浏览器发现需要渲染引擎去渲染新的元素时,浏览器会通知渲染引擎,这个过程是需要消耗时间的。

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

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

    属性同步

    • 标准属性
      对div1的标准属性的修改,会被浏览器同步到页面中,比如id、class Name、title等
    • data-*属性
      同上
    • 非标准属性
      对非标准属性的修改,则只会停留在JS线程中,不会同步到页面里。
      启发:如果你有自定义属性,又想被同步到页面中,请使用data- 作为前缀作为属性名。


      非标准属性.png
      示意图.png

    Property 与 Attribute 的区别

    • property属性
      JS线程中div1 对象的所有属性,叫做div1的 property
    • attribute也是属性
      渲染引擎中div1对应标签的属性,叫做attribute,或者说页面标签中的属性
    • 区别
      大部分时候,同名的property和attribute值相等,但如果不是标准属性,那么它俩只会在一开始时相等。但注意attribute只支持字符串,而property支持字符串、布尔等类型。

    相关文章

      网友评论

        本文标题:JS中DOM编程总结

        本文链接:https://www.haomeiwen.com/subject/fprtlltx.html