JS 编程接口之 DOM 编程

DOM 简介

网页其实是一棵树

image-20210503211900220.png

image-20210503211930116.png

JS如何操作这棵树

浏览器往window上加一个document即可,JS用document操作网页,这就是Document Object Model 文档对象模型

image-20210503212452890.png

API

获取元素,也叫标签

有很多API

window.idxxx	//或直接 idxxx,最简单的方法,但有时会有冲突

document.getElementByld('idxxx')
document.getElementsByTagName('div')[0]
document.getElementsByClassName('red')[0]//这三种方法复杂不常用

document.querySelector('#idxxx') //注意加#号
document.querySelectorAll('.red')[0]//这两种方法是常用的
复制代码

获取特定元素

获取html元素

document.ducumentElement

获取head元素

document.head

获取body元素

document.body

获取窗口(窗口不是元素)

window

获取所有元素

document.all

document.all是ie发明的,是第6个falsy值。

image-20210503214348364.png

元素的6层原型链

我们获取到的元素是一个对象,所以需要搞清楚它的原型。

console.dir(div1)看原型链——

第一层原型

HTMLDivElement.prototype,这里面是所有div共有的属性。

第二层原型

HTMLElement.prototype,这里面是所有HTML标签共有的属性。

第三层原型

Element.prototype,这里面是所有XML、HTML标签的共有属性(浏览器不止展示HTML)

第四层原型

Node.prototype,这里面是所有节点的共有属性,节点包括XML标签文本注释、HTML标签文本注释等等。

第五层原型

EventTarget.prototype,里面最重要的函数属性是addEvenListener

第六层原型

Object.prototype

div 原型链

节点

节点和元素的区别

Node?Element?

节点Node包括以下几种,其中就包括Element

MDN有完整描述x.nodeType得到一个数字。

image-20210503220502942.png

节点的增删改查

  • 创建一个标签节点

    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.appenChild('你好')
    复制代码
  • 插入页面中

    创建的标签默认处于JS线程中,必须把它插到head后者body里面,它才会生效。

    document.body.appendChild(div)

    或者

    已在页面中的元素.appendChild(div)

appendChild题目

页面中有 div#test1 和 div#test2
let div = document.createElemnt('div')
test1.appendChild(div)
test2.appendChild(div)
复制代码

请问最终div出现在哪里?

=> test2 里面,一个元素不能同时出现在两个地方,除非复制一份。

  • 两种方法

    旧方法:parentNode.removeChild(childNode)

    新方法:childNode.remove() //ie不支持

  • 思考

    如果一个node被移出页面(DOM树),那么它还能再次返回页面中吗?

    可以。

    怎样删除node呢?

    div = null

  • 改属性

    • 改标准属性

      • 改id

        div1.id = 'div1'
        复制代码
      • 改class

        //class是JS保留字,不能直接用div1.class
        div1.className = 'blue'	//会全覆盖,想再添加只能 div1.className += ' red'
        div1.classList.add('green')	//class = "blue red green"
        复制代码
      • 改style

        div1.style = 'width: 100px; color: blue;'
        div1.style.width = '200px'	//改style的一部分
        复制代码

        当改动类似于background-color这种有中划线的属性时,改写为div1.style.backgroundColor就可以执行。

      • 改data-* 属性

        div1.dataset.x='river'
        复制代码
    • 读标准属性

      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)
    复制代码
  • 查爸爸

    node.parentNode
    或
    node.parentElement
    复制代码
  • 查爷爷

    node.parentNode.parentNode
    复制代码
  • 查子代

    node.childNodes
    或者
    node.children
    复制代码
    • 第一个问题:

      下面console.log(test.childNodes.length)打印结果为7,依次为text,li,text,li,text,li,text。

      text是回车+空格

      image-20210503235941641.png

      因此下面这个打印结果就是3

      image-20210504000158570.png

      用children就可以避免这种情况,多用children!!

      image-20210504000252183.png

    • 第二个问题:

      当子代变化时,两者也会实时变化吗?

      会实时变化。

      image-20210504000523276.png

      image-20210504000544775.png

      document.querySelectorAll('li')就不会实时变化

      image-20210504000733992.png

  • 查兄弟姐妹

    node.parentNode.childNodes	//还要排除自己
    node.parentNode.children	//还要排除自己
    复制代码

    也就是要做两件事情,第一件是上面的找到parent的孩子,第二件就是遍历这个数组并且排除自己。

    操作示例:

    div1的parent共有35个孩子

    image-20210504001320239.png

    通过遍历并排除掉div1自己,得到自己的兄弟姐妹数组siblings

    image-20210504001425762.png

  • 查看老大

    node.firstChild
    复制代码
  • 查看老幺

    node.lastChild
    复制代码
  • 查看上一个哥哥/姐姐

    node.previousSibling	//有可能会查看到文本节点
    node.previousElementSibling
    复制代码
  • 查看下一个弟弟/妹妹

    node.nextSibling
    node.nextElementSibling
    复制代码
  • 遍历一个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 操作是跨线程的

浏览器功能分为渲染引擎和JS引擎,渲染引擎用来渲染HTML和CSS,JS引擎来操作JS。

跨线程操作

各线程各司其职

JS引擎不能操作页面,只能操作JS

渲染引擎不能操作JS,只能操作页面

document.body.appendChild(div1)这句话是如何改变页面的呢?

跨线程通信

当浏览器发现JS在body里面加了个div1对象

浏览器就会通知渲染引擎在页面里也新增一个div元素

新增的div元素所有属性都照抄div1对象

注意:一个是对象,一个是元素。

image-20210504002943572.png

插入新标签的完整过程

在div1放入页面之前

对div1所有的操作都属于JS线程内的操作

把div1放入页面之时

浏览器发现JS的意图,就会通知渲染线程在页面中渲染div1对应的元素

把div1放入页面之后

你对div1的操作都有可能会触发重新渲染

div1.id='newId'可能会重新渲染,也可能不会

div1.title='new'可能会重新渲染,也可能不会

如果连续对div1多次操作,浏览器可能会合并成一次操作,也可能不会,就比如下面这个例子,如果不加test.clientWidth,那JS就会默认合并导致动画无法显示。

image-20210504003554460.png

属性同步

标准属性

对div1的标准属性修改,会被浏览器同步到页面中

比如id、className、title等

data-* 属性

同上

非标准属性

对非标准属性的修改,则只会停留在JS线程中,不会同步到页面里

比如x属性,示例代码

image-20210504004540231.png

启示

如果你有自定义属性,又想被同步到页面中,请使用data-作为前缀

Property V.S. Attribute

property 属性

JS线程中div1的所有属性,叫做div1的property

attribute属性

渲染引擎中div1对应标签的属性,叫做attribute

区别

大部分时候,同名的property 和 attribute 值相等

但如果不是标准属性,那么它俩只会在一开始时相等

但注意attribute只支持字符串

而property支持字符串、布尔等类型

什么叫封装

举例

电脑笔记本就是CPU、内存、硬盘、主板、显卡的封装,用户只需要接触显示器、键盘、鼠标、触控板等设备,即可操作复杂的计算机。

接口

被封装的东西需要暴露一些功能给外部,这些功能就是接口,如USB接口、HDMI接口。

设备只要支持这些接口,即可与被封装的东西通讯,比如键盘、鼠标支持USB接口,显示器支持HDMI接口。

image-20210504014710620.png

image-20210504014719342.png

术语

我们把提供给其他人用的工具代码叫做库,比如JQuery、Underscore

API

库暴露出来的函数或属性就叫做API(应用编程接口)

框架

当库变得很大,并且需要学习才能看懂,那么这个库就是框架,比如Vue 、React

DOM封装

源码

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享