Skip to content

一. 什么是DOM?


1. 认识DOM和BOM

  • 前面我们花了很多时间学习js的基本语法,但是这些基本语法,但是这些语法好像和做网页没有什么关系,和前面学习的HTMLCSS也没有什么关系呢?

    • 这是因为我们前面学习的部分属于ECMAScript,也就是**js本身的语法部分**
    • 除了语法部分之外,我们还需要学习浏览器提供给我们开发者的**DOMBOM相关的API才能对页面、浏览器进行操作**
  • 前面我们学习了一个window的全局对象,window上事实上就包含了这些内容:

  • 我们已经学习了js语法部分的ObjectArrayDate

  • 另外还有DOMBOM部分

    image-20220518001252547
  • DOM文档对象模型Document Object Model

    • 简称 DOM将页面所有的内容表示为可以修改的对象
  • BOM浏览器对象模型Browser Object Model

    • 简称 BOM由浏览器提供的用于处理除文档(document)之外的所有内容的其他对象
    • 比如navigatorlocationhistory等对象

2. 深入理解DOM

  • 浏览器会对我们编写的HTMLCSS进行渲染,同时它又要考虑我们可能会通过js来对其进行操作:

    • 于是浏览器将我们编写在**HTML中的每一个元素**(Element)都抽象成了一个个对象
    • 所有这些对象可以通过js来对其进行访问,那么我们就可以通过js来操作页面
    • 所以,我们将这个抽象过程称之为 文档对象模型Document Object Model
  • 整个文档被抽象到document对象中

    • 比如document.documentElement对应的是**html元素**
    • 比如document.body对应的是**body元素**
    • 比如document.head对应的是**head元素**
  • 下面的一行js代码可以让整个页面变成红色:

    js
    document.body.style.backgroundColor = 'red'
  • 所以我们学习DOM,就是在学习如何通过js对文档进行操作的

  • 个人理解:

    • DOM就是浏览器提供给我们用来对整个文档进行操作的,将HTML所有元素抽象成了一个个对象,允许使用js进行操作访问等

二. 认识DOM Tree


  • 一个页面不只是有htmlheadbody元素,也包括很多的子元素:
    • html结构中,最终会形成一个树结构

    • 抽象成DOM对象的时候,它们也会形成一个树结构,我们称之为DOM Tree

      image-20220518233908548

三. DOM的整体结构


1. DOM的学习顺序

  • DOM相关的API非常多,我们会通过如下顺序来学习:
    • DOM元素之间的关系
    • 获取DOM元素
    • DOM节点的typetagcontent
    • DOM节点的attributesproperty
    • DOM节点的创建、插入、克隆、删除
    • DOM节点的样式、类
    • DOM元素/window的大小、滚动、坐标
  • 整体会按照这个顺序来学习,也会额外补充其他的知识

2. DOM的继承关系图

  • DOM相当于是jsHTMLCSS之间的桥梁

    • 通过浏览器提供给我们的DOM API,我们可以对元素以及其中的内容做任何事情
  • 类型之间有如下的继承关系:

    • 所有元素继承Element基类
    • Element基类又继承Node
    image-20220518234639205

3. document对象

  • document对象是Document类的实例对象

  • document对象下的所有对象都有继承自Element

  • document对象是DOM入口对象

  • Document节点表示的整个载入的网页,它的实例是全局的document对象:

    • DOM的所有操作都是从document对象开始的
    • 它是**DOM的入口点**,可以从document开始去访问任何节点元素
  • 对于最顶层的htmlheadbody元素,我们可以直接在document对象中获取到:

    js
    document.doctype // 文档声明 <!DOCTYPE html>
    document.documentElement // html元素 <html> 
    document.head // head元素 <head>
    document.body // body元素 <body>

四. 节点、元素导航


1. 节点(Node)之间的导航(navigator)

  • 如果我们获取到一个节点后,可以根据这个节点去获取其他的节点,我们称之为节点之间的导航

    • 节点范畴:文本节点(换行符、空格等)、注释节点commentbody节点、html节点、script节点、div节点等其他节点...
  • 节点之间存在如下的关系:

    关系
    parentNode父节点
    previousSibling前兄弟节点
    nextSibling后兄弟节点
    childNodes子节点
    firstChild第一个子节点
    lastChild最后一个子节点
    image-20220520160822279
    html
    <body>
      <div class="box">
        <!-- 这是注释节点 -->
        <h1>标题</h1>
        <div>div2</div>
        <div>div2</div>
      </div>
    
      <script>
        var boxEl = document.querySelector('.box')
        console.log(boxEl.parentNode) // 父节点 body
        console.log(boxEl.previousSibling) // 前兄弟节点 #text(文本节点)
        console.log(boxEl.nextSibling) // 后兄弟节点 #text(文本节点)
        console.log(boxEl.childNodes)  // NodeList(9) [text, comment, text, h1, text, div, text, div, text]
        console.log(boxEl.firstChild) // 第一个子节点 #text
        console.log(boxEl.lastChild) // 最后一个子节点 #text
      </script>
    </body>

2. 元素(Element)之间的导航(navigator)

  • 如果我们获取到一个元素后,可以根据这个元素去获取其他的元素,我们称之为元素之间的导航

    • 元素范畴body元素、html元素、script元素、div元素等其他元素,文本和注释不属于元素
  • 元素之间存在如下的关系:

    关系
    parentElement父元素
    previousElementSibling前兄弟元素
    nextElementSibiling后兄弟元素
    children子元素
    firstElementChild第一个子元素
    lastElementChild最后一个子元素
    image-20220520183238101
    html
    <body>
      <div class="box">
        <h1>标题</h1>
        <div>div2</div>
        <div>div2</div>
      </div>
    
      <script>
        var boxEl = document.querySelector('.box')
        console.log(boxEl.parentElement) // 父元素 body
        console.log(boxEl.previousElementSibling) // 前兄弟元素 不存在 则为null
        console.log(boxEl.nextElementSibling) // 后兄弟元素 script
        console.log(boxEl.children)  // HTMLCollection(3) [h1, div, div]
        console.log(boxEl.firstElementChild) // 第一个子元素 h1
        console.log(boxEl.lastElementChild) // 最后一个子元素 div
      </script>
    </body>

3. 表格table元素之间的导航navigator

  • table 元素支持以下这些属性(包括上面给出的):

    属性含义
    table.rows<tr> 元素的集合
    table.caption / tHead / tFoot引用元素 <caption><thead><tfoot>
    table.tBodies<tbody> 元素的集合
  • <thead><tfoot><tbody> 元素提供了rows 属性:

    • tbody.rows : 表格内部 <tr>元素的集合
  • <tr>

    属性含义
    tr.cells在给定 <tr>中的<td><th>单元格的集合
    tr.sectionRowIndex给定的<tr>在封闭的<thead> / <tbody> / <tfoot>中的位置(索引)
    tr.rowIndex在整个表格中<tr>的编号(包括表格的所有行)
  • <td><th>

    • td.cellIndex :在封闭的 <tr> 中单元格的编号

4. 表单form元素的导航navigator

  • form 元素可以直接通过document来获取:document.forms

  • form 元素中的内容可以通过elements来获取:form.elements

  • 我们可以设置表单子元素的name来获取它们

    html
    <body>
      <form action="">
        <input name="account" type="text">
        <input name="password" type="password">
        <input name="sex" type="sex">
        <select name="fruits" id="fruits">
          <option value="apple">苹果</option>
          <option value="orange">橘子</option>
        </select>
      </form>
    
      <script>
        var formEl = document.forms[0]
        var els = formEl.elements
        console.log(formEl) // form元素
        console.log(els) // HTMLFormControlsCollection(4) [input, input, input, select#fruits, account: input, password: input, sex: input, fruits: select#fruits]
        window.onclick = function() {
          console.log(els.account.value)
          console.log(els.password.value)
          console.log(els.sex.value)
          console.log(els.fruits.value)
        }
      </script>
    </body>

五. 获取元素的方法


  • 当元素彼此靠近或者相邻时,DOM 导航属性(navigation property)非常有用

    • 但是,在实际开发中,我们希望可以任意的获取到某一个元素应该如何操作呢?
  • DOM 为我们提供了获取元素的方法:

    方法名搜索方式可以在元素上调用?实时的?
    querySelectorCSS-selector可以不是
    querySelectorAllCSS-selector可以不是
    getElementByIdid不可以不是
    getElementsByNamename不可以
    getElementsByTagNametag or '*'可以
    getElementsByClassNameclass可以
html
<body>
  <div class="box">
    <h1>标题</h1>
    <div>div1</div>
    <div>div2</div>
  </div>
  
  <script>
    var divEl1 = document.querySelector('div') // 匹配第一个符合条件的元素
    console.log(divEl1) // div.box
    var divEl2 = document.querySelectorAll('div') 
    console.log(divEl2) // NodeList(3) [div.box, div, div]
    var divEl4 = document.getElementsByTagName('div') // 实时获取
    console.log('divEl4: ', divEl4) // HTMLCollection(3) [div.box, div, div], 点开查看会有包含后续增加的divEl4元素,浏览器会实时更新
    setTimeout(function() {
      var divEl3 = document.createElement('div')
      divEl1.append(divEl3)
      console.log('添加')
    }, 2000)
  </script>
</body>
  • 开发中如何选择呢?
    • 目前最常用的是querySelectorquerySelectAll
    • getElementById偶尔也会使用或者在适配一些低版本浏览器时

六. Node节点的属性


1. 节点的属性 - nodeType

  • 目前,我们已经可以获取到节点了,接下来我们来看一下节点中有哪些常见的属性:

    • 当然,不同的节点类型有可能有不同的属性
    • 这里我们主要讨论节点共有的属性
  • nodeType属性:

    • nodeType属性提供了一种获取节点类型的方法
    • 它有一个数值型值(numeric value
  • 常见的节点类型有如下:

    常量描述
    Node.ELEMENT_NODE1一个元素节点,例如:<p><div>
    Node.TEXT_NODE3Element或者Attr中实际的文字
    Node.COMMENT_NODE8一个Comment节点
    Node.DOCUMENT_NODE9一个Document节点
    Node.DOCUMENT_TYPE_NODE10描述文档类型的DocumentType节点。
    例如:<!DOCTYPE html>就是用于HTML5
  • 其他类型可以查看MDN文档: https://developer.mozilla.org/zh-CN/docs/Web/API/Node/nodeType

    html
    <body>
      <!-- 这是一个注释节点 -->
      这是一个文本节点
      <div class="box">
        <h1>标题</h1>
        <div>div1</div>
      </div>
    
      <script>
        var divEl1 = document.querySelector('div') // 匹配第一个符合条件的元素 div.box
        var h1El = document.querySelector('h1') 
        var bodyEl = document.querySelector('body')
        console.log(divEl1.nodeType, h1El.nodeType, bodyEl.nodeType) // 1 1 1
    
        var textNode = document.body.childNodes[2]
        var commentNode = document.body.childNodes[1]
        console.log(textNode.nodeType, commentNode.nodeType) // 3 8
    
        var documentNode = document
        console.log(documentNode.nodeType) // 9
    
        var documentDescNode = document.doctype
        console.log(documentDescNode.nodeType) // 10
    
        console.log(Node.DOCUMENT_TYPE_NODE) // 10
      </script>
    </body>

2. 节点的属性 - nodeName、tagName

  • nodeName获取node节点的名字

  • tagName获取元素的标签名字

    html
    <body>
      <!-- 这是一个注释节点 -->
      这是一个文本节点
      <div class="box">
        <h1>标题</h1>
        <div>div1</div>
        <div>div2</div>
      </div>
      
      <script>
        var divEl1 = document.querySelector('div')
        var h1El = document.querySelector('h1') 
        var bodyEl = document.querySelector('body')
        var textNode = document.body.childNodes[2]
        var commentNode = document.body.childNodes[1]
        var documentNode = document
        var documentDescNode = document.doctype
    
        console.log(divEl1.nodeName, divEl1.tagName) // DIV DIV
        console.log(h1El.nodeName, h1El.tagName) // H1 H1
        console.log(bodyEl.nodeName, bodyEl.tagName) // BODY BODY
        console.log(textNode.nodeName, textNode.tagName) // #text undefined
        console.log(commentNode.nodeName, commentNode.tagName) // #comment undefined
        console.log(documentNode.nodeName, documentNode.tagName) // #document undefined
        console.log(documentDescNode.nodeName, documentDescNode.tagName) // html undefined
      </script>
    </body>
  • tagName nodeName之间有什么不同呢?

    • tagName 属性仅适用于Element节点
    • nodeName 是为任意Node定义的:
      • 对于元素,它的意义与tagName相同,所以使用哪一个都是可以的
      • 对于其他节点类型(textcomment 等),它拥有一个对应节点类型的字符串

3. 节点的属性 - innerHTML、textContent

节点的属性作用
innerHTML 获取节点中的内容(包含HTML,不包含节点本身)
outerHTML包含了节点完整的HTML,等同于innerHTML + 节点本身
textContent获取节点中所有的文本内容(包括子元素中的文本内容)
  • innerHTMLtextContent的区别:

    • 使用 innerHTML,我们将其 "作为HTML" 插入,可带有HTML标签
    • 使用 textContent,我们将其 "作为文本" 插入,所有符号(symbol)均按字面意义处理
      • 性能好于innerHTML,设置textContent只修改元素中的文本,设置innerHTML修改整个元素
    image-20220521001145941

4. 节点的属性 - nodeValue

  • 用于获取非元素节点(text、comment)的文本内容

    html
    <body>
      <!-- 这是一个注释节点 -->
      这是一个文本节点
      <div class="box">
        <h1>标题</h1>
      </div>
      
      <script>
        var divEl1 = document.querySelector('div') // 匹配第一个符合条件的元素
        console.log(divEl1.previousSibling.nodeValue) // 这是一个文本节点
        console.log(divEl1.previousSibling.data) // 这是一个文本节点
      </script>
    </body>

5. 节点的其他属性

  • hidden属性:也是一个全局属性,可以用于设置元素隐藏

    html
    <body>
      <div class='box'>哈哈哈</div>
    
      <script>
        var box = document.quertSelector('.box')
        box.hidden = true // 隐藏元素,不占据页面位置,但DOM结构中存在
      </script>
    </body>
  • DOM 元素还有其他属性:

    • value
      • <input><select> <textarea>(HTMLInputElement,HTMLSelectElement……) value
    • href
    • <a href="...">(HTMLAnchorElement) href
    • id
      • 所有元素(HTMLElement)的 “id” 特性(attribute)的值
  • classstyle我们会在后续专门讲解的

Released under the MIT License.