DOM

136 阅读8分钟

DOM

概述

DOM 全称(document object model 文档对象模型),主要用于操作对应的html文档中的内容。document是它的超类。

DOM中的对象

HTMLElement (元素对象 主要是标签)

Attribute (属性对象 主要是标签中的属性)

Text (文本对象 主要是 里面的文本内容)

Node (节点对象 包含html中的所有节点 )

浏览器渲染HTML过程

  • 抽取对应的DOM树 (抽取html中的所有内容构成一个树状结构)
  • 抽取css规则树 (抽取css样式构成css规则树)
  • DOM树和css规则树进行合并形成渲染树(render Tree)(js会阻塞渲染树的形成)进行渲染

DOM树的结构

html代码
<!DOCTYPE HTML>
<html>
	<head>
        <title>文档标题</title>
    </head>
    <body>
        <a href='http://www.baidu.com'>我的链接</a>
        <h1>
            我的标题
        </h1>
    </body>
</html>
树状图

DOM的相关操作

获取元素的操作(document 、HTMLElement的相关方法)*

  • getElementById 通过id获取元素 返回的是一个元素对象
  • getElementsByClassName 通过class来获取 返回的是HTMLCollection (伪数组)
  • getElementsByTagName 通过标签名进行获取 返回的是HTMLCollection (伪数组)
  • getElementsByName 通过name属性获取 返回的是NodeList (伪数组)
  • querySelector 通过选择器获取第一个找到的元素 返回是的元素对象
  • querySelectorAll 通过选择器获取全部的元素 返回的是NodeList (伪数组)
//获取元素的方法
//兼容问题 获取元素的方法存在兼容问题 
//通过id获取 传入一个id的值 元素对象 HTMLElement
console.log(document.getElementById('box'))
//通过className获取  HTMLCollection html集合 兼容问题
console.log(document.getElementsByClassName('content'))
// 通过name属性获取 NodeList 节点列表 兼容问题
console.log(document.getElementsByName('jack'))
//通过标签名获取 HTMLCollection html集合
console.log(document.getElementsByTagName('div'))
//通过传入的选择器获取第一个找到的元素  HTMLElement 兼容问题
console.log(document.querySelector('.content'))
//通过传入的选择器获取所有的元素 NodeList 节点列表 兼容问题
console.log(document.querySelectorAll('.content'))
var element = document.querySelector('.content')
//通过element来获取里面的元素
console.log(element.getElementsByClassName('text')[0])

伪数组特性 下标访问、length属性

HTMLCollection 和 NodeList的区别

HTMLCollection 是即时更新的(live);当其所包含的文档结构发生改变时,它会自动更新

NodeList 是一个静态集合,也就意味着随后对文档对象模型的任何改动都不会影响集合的内容(相当于是一个快照)

关于document的相关属性 *

  • document.body 获取body
  • document.head 获取head
  • document.forms 获取所有的表单 (伪数组)
  • document.cookie 获取cookie
  • rootElement 包含文档的元素 默认为null
  • documentElement 文档元素(html)
  • .....
//document的相关属性
console.log(document.body) //获取body
console.log(document.head) //获取head
console.log(document.forms) //获取所有的表单 HTMLCollection
console.log(document.cookie) //获取cookie
console.log(document.rootElement) //获取根元素
console.log(document.documentElement) //获取文档元素

元素的相关属性 *

所有元素都具备的属性 (可设置可获取)
  • title 标题
  • tagName 标签名 (只读)
  • id id值
  • className class的值
  • classlist class值的列表 (add remove toggle)
  • style 样式设置
  • innerHTML、innerText (双标签情况才起作用)
  • textContent 文本内容 (类似于innerText)
<div class="inner">
    <!--哈哈哈-->
    <b>你好</b></div>
<script>
    //获取div
    var div = document.querySelector('div')
    console.log(div.title) //标题
    div.title = '你好'
    console.log(div.tagName) //标签名 全大写英文 只读的
    // div.tagName = 'A' 无用的
    console.log(div.id) //id值
    div.id = 'content'
    console.log(div.className) //class名字
    div.className = 'box' //直接覆盖class
    console.log(div.classList) //class列表 
    //添加class的值
    div.classList.add('context') //原本上面添加样式
    //移除样式值
    // div.classList.remove('box')
    div.classList.remove('context')
    //有就是删除 没有就添加
    div.classList.toggle('box')
    console.log(div.style) //样式
    // div.style.样式名(驼峰命名法)
    div.style.backgroundColor = 'red'
    console.log(div.innerHTML) //显示的html 解析html的特性 (容易被xss攻击)
    div.innerHTML = '<i>我是修改的内容</i>'
    console.log(div.innerText) //显示的文本 
    div.innerText = '<i>我是修改的内容</i>'
    //获取标签内的所有的内容 类似于innerText 它抽取所有的显示的文本内容
    console.log(div.textContent)
    div.textContent = '哈哈哈哈'
</script>
关于对象的属性 元素的属性
对象属性 (不会显示在DOM上)
var obj = {}
obj.name = 'jack'
元素属性 (显示在DOM上)
var element = new HTMLElement()
element.id = 'box'
元素属性的特性(相关的元素属性)

元素默认就携带的属性称为初始属性 (所有的初始属性都可以直接被.出来)

<div username="jack"></div>
<img src="" alt="">
<input type="text" value="" placeholder="">
<script>
    //获取元素对象
    var div = document.querySelector('div')
    //指定对象属性 内存中分配给当前div这个元素对象 并不会显示到这个div的dom上面
    console.log(div.hello) //undefined
    div.hello = '你好'
    console.log(div.hello) //您好
    //元素属性 (元素本身就有的属性 元素属性可以直接点出来)
    console.log(div.id) //空字符串
    div.id = 'box' //显示到dom上
    console.log(div.id) //box
    //非元素属性不能直接点出来
    console.log(div.username) //undefined
    //获取元素对象
    var div = document.querySelector('div')
    //指定对象属性 内存中分配给当前div这个元素对象 并不会显示到这个div的dom上面
    console.log(div.hello) //undefined
    div.hello = '你好'
    console.log(div.hello) //您好
    //元素属性 (元素本身就有的属性 元素属性可以直接点出来)
    console.log(div.id) //空字符串
    div.id = 'box' //显示到dom上
    console.log(div.id) //box
    //非元素属性不能直接点出来
    console.log(div.username) //undefined
    //img的src属性
    console.log(document.querySelector('img').src)
    //input的value属性
    console.log(document.querySelector('input').value)
</script>
  • img 的src 和 alt
  • input 的type 和 value 及 placeholder
  • a 标签 href属性 target属性
  • .....
元素属性操作的相关方法 (可以操作任意属性)元素对象的方法 *
  • getAttribute 获取属性

    //element.getAttribute(atributeName) 通过属性名获取属性值返回对应的属性值
    
  • setAttribute 设置属性

    //element.setAttribute(attributeName,attributeValue)
    
  • removeAttribute 删除属性

    //element.removeAttribute(attributeName) 通过属性名删除属性
    
    示例
    <div hello="你好"></div>
      <script>
        var div = document.querySelector('div')
        //操作任意属性  初始属性 自定义属性
        //getAttribute 只能你的dom元素上写没有写 没写就null
        console.log(div.getAttribute('id')) //null
        console.log(div.getAttribute('hello')) // 你好
        console.log(div.getAttribute('class')) // null
        //setAttribute 将对应的属性设置到dom元素上 显示上去
        div.setAttribute('class','box')
        div.setAttribute('username','jack')
        console.log(div.username)//undefined
        //removeAttribute 通过属性名移除对应的属性 完全不显示
        div.removeAttribute('class')
        // div.getElementsByTagNameNS  NS  namespace 命名空间
      </script>
    

样式获取 *

使用style标签获取样式
//通过style来获取样式 (style属性常用于设置样式而少用于获取样式)
console.log(div.style.color)
//通过style获取样式 只能获取内嵌的style中写了的样式 其他是无法获取的
console.log(div.style.backgroundColor) //空字符
console.log(div.style.fontSize) //空字符
使用getComputedStyle来获取样式 *
//通过全局方法 getComputedStyle来获取样式 传入对应的element对象 返回对应的样式对象
console.log(getComputedStyle(div))
//获取style内嵌的样式
console.log(getComputedStyle(div).color) //转为rgb颜色
//获取style标签中的样式
console.log(getComputedStyle(div).backgroundColor) //转为rgb颜色
//针对每个样式是存在默认值的
console.log(getComputedStyle(div).fontSize)
兼容写法
//getComputedStyle存在兼容问题 ie低版本兼容
// 兼容写法 currentStyle来兼容低版本
function getStyle(ele){
    return getComputedStyle?getComputedStyle(ele):ele.currentStyle
}

重绘和回流 ***

回流

回流又叫重排(对于页面的布局进行重新排列)。

触发回流的要求

当前对应的页面的内容的位置布局等发生变化

获取某些属性的时候需要计算对应的位置获取距离的时候 (offsetTop offsetLeft....)

重绘

重绘就是重新绘制,也就是说对应的页面进行重新渲染

触发重绘的要求

页面的内容或者样式发生更改就会触发

回流必定重绘、重绘不一定回流

相关总结

重绘和回流会影响对应的渲染性能,重绘和回流的次数越多那么性能越差 (避免重绘回流)

避免重绘回流

减少dom操作

减少css操作 (设置样式尽量使用class来指定)

....

Node *

节点的分类

  • 元素节点 Element
  • 属性节点 attribute
  • 文本节点 textNode
节点对应的属性
  • nodeType 节点类型
  • nodeValue 节点值
  • nodeName 节点名
nodeTypenodeNamenodeValue
Element1标签名(类似元素的tagName)null
Attribute2属性名属性值
TextNode3#text文本值
//获取元素
var div = document.querySelector('div')
//元素节点
console.log(div.nodeName) //DIV 类似于tagName 标签名
console.log(div.nodeType) //1 表示当前是一个元素节点
console.log(div.nodeValue) //null
//属性节点
//元素节点的相关属性 attributes 获取所有的属性节点
console.log(div.attributes) //伪数组 NamedNodeMap 
//取出对应的属性节点对象
console.log(div.attributes[0])  // class='box' 它是一个属性节点对象
console.log(div.attributes[0].nodeType) //2
console.log(div.attributes[0].nodeName) //class
console.log(div.attributes[0].nodeValue) //box
//文本节点  childNodes 子节点
console.log( div.childNodes[0]) //文本节点对象
console.log(div.childNodes[0].nodeName) //#text
console.log(div.childNodes[0].nodeType) //3
console.log(div.childNodes[0].nodeValue) //aaa

节点的属性 (获取不到返回null)**

  • attributes 获取该元素所有的属性节点的集合 (伪数组)
  • childNodes 获取该元素下的所有元素节点及文本节点的集合 (NodeList)
  • children 获取该元素下的所有的元素节点的集合(HTMLCollection)
  • lastChild 最后一个子节点 (文本节点和元素节点)
  • lastElementChild 最后一个子元素节点
  • firstChild 第一个子节点(文本节点和元素节点)
  • firstElementChild 第一个子元素节点
  • parent 获取该元素的父节点
  • parentElement 获取该元素的父元素节点
  • previousSibling 前一个兄弟节点 (包含文本节点和元素节点)
  • previousElementSibling 前一个兄弟元素节点
  • nextSibling 后一个兄弟节点 (包含文本节点和元素节点)
  • nextElementSibling 后一个兄弟元素节点

节点相关方法 **

创建节点的方法(document)
  • createElement 创建元素节点
  • createAttribute 创建属性节点
  • createTextNode 创建文本节点
  • createDocumentFragmen 创建文档片段
//传入对应的标签名 返回一个新的元素
var element = document.createElement('div')
console.log(element)
//创建属性节点 传入对应的属性名
var attr = document.createAttribute('name')
//通过value属性来设置属性对象的属性值
attr.value = 'jack'
console.log(attr)
//创建文本节点 传入对应的文本
var text = document.createTextNode('我是文本')
console.log(text)
//创建文档片段 里面的方法其实就是document中的元素里面的方法
//里面存储多个元素 一次性添加 里面可以包含多个内容
var fragment = document.createDocumentFragment()
console.log(fragment.nodeType)
节点操作的方法
添加节点的方法

append 支持多个参数 支持字符串(追加到后面)

appendChild 只有一个参数 不支持字符串(追加到后面)

insertBefore 插入到对应的子元素的前面

insertAdjacentHTML 插入对应的html代码到指定位置

insertAdjacentText 插入对应的文本到指定位置

insertAdjacentElement 插入对应的元素到指定位置

//定位修饰
'beforebegin':元素自身的前面。
'afterbegin':插入元素内部的第一个子节点之前。
'beforeend':插入元素内部的最后一个子节点之后。
'afterend':元素自身的后面。
克隆节点的方法

cloneNode 将当前节点进行克隆返回新的节点(传入boolean类型的值 true 深度克隆 false为浅度克隆)

//cloneNode 克隆节点 返回一个新的node对象 传入boolean类型的值 如果为true表示深度克隆 如果为false表示只克隆第一层
console.log(element.cloneNode(true) == element) //false
删除节点

removeChild 删除子节点

//移除子元素 传入子元素
div.removeChild(div.children[0])

remove 删除自身

//remove方法 删除自己
div.remove()
封装删除空文本节点的方法
//  删除空文本节点
function removeEmptyText(node){
    //判断类型
    if(!(node instanceof Node)){
        throw new Error('类型错误')
    }
    //遍历所有的节点
    for(var i=0;i<node.childNodes.length;i++){
        //判断是否为空
        if(node.childNodes[i].nodeType == 3 && node.childNodes[i].nodeValue.trim().length==0){
            node.removeChild(node.childNodes[i])
        }
    }
}
替换的相关方法

replaceChild 替换子节点

replaceChildren 替换里面的所有内容

replaceWith 将自身进行替换

//获取div
var div = document.querySelector('div')
//替换里面的b标签 
var i = document.createElement('i')
var a = document.createElement('a')
//替换子节点 可以替换元素节点 文本节点
// 传入用于替换的节点 传入子节点
div.replaceChild(i,div.children[0]) //用i标签替换div的第一个子元素
div.replaceChild(a,div.childNodes[2]) //用a标签替换div的第三个节点
//替换元素 替换自身的所有内容 支持传入节点和字符串 支持多个 传入用于替换的内容
div.replaceChildren('hello','world',i) //用传入的内容替换div中所有内容
//replaceWith 将自身进行替换 支持传入节点和字符串 支持多个 传入用于替换的内容
div.replaceWith('替换的内容') //用传入的内容替换div本身