JavaScript的DOM操作(一)

一、什么是DOM?

1.认识DOM和BOM

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

  • 这是因为我们前面学习的部分属于ECMAScript,也就是JavaScript本身的语法部分;
  • 除了语法部分之外,我们还需要学习浏览器提供给我们开发者的DOM、BOM相关的API才能对页面、浏览器进行操作

前面我们学习了一个window的全局对象,window上事实上就包含了这些内容:

  • 我们已经学习了JavaScript语法部分的Object、Array、Date等;
  • 另外还有DOM、BOM部分;

DOM:文档对象模型(Document Object Model)

  • 简称 DOM,将页面所有的内容表示为可以修改的对象

BOM:浏览器对象模型(Browser Object Model)

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

2.深入理解DOM

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

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

整个文档被抽象到 document 对象中:

  • 比如document.documentElement对应的是html元素;
  • 比如document.body对应的是body元素;
  • 比如document.head对应的是head元素;

下面的一行代码可以让整个页面变成红色:

document.body.style.backgroundColor = "red";

所以我们学习DOM,就是在学习如何通过JavaScript对文档进行操作的;

二、认识DOM Tree

1.DOM Tree的理解

一个页面不只是有html、head、body元素,也包括很多的子元素:

  • 在html结构中,最终会形成一个树结构

  • 在抽象成DOM对象的时候,它们也会形成一个树结构,我们称之为DOM Tree
    JavaScript的DOM操作(一)_第1张图片

2.DOM 的学习顺序

DOM相关的API非常多,我们会通过如下顺序来学习:

  1. DOM元素之间的关系 (父子关系、兄弟关系)

  2. 获取DOM元素 (通过id、class、属性、标签名)

  3. DOM节点的type、tag、content

  4. DOM节点的attributes、properies

  5. DOM节点的创建、插入、克隆、删除

  6. DOM节点的样式、类

  7. DOM元素/window的大小、滚动、坐标

整体会按照这个顺序来学习,也会额外补充其他的知识。

3.DOM的继承关系图

DOM相当于是JavaScript和HTML、CSS之间的桥梁

  • 通过浏览器提供给我们的DOM API,我们可以对元素以及其中的内容做任何事情;

类型之间有如下的继承关系

JavaScript的DOM操作(一)_第2张图片

4.document对象

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

  • 对DOM的所有操作都是从 document 对象开始的;
  • 它是DOM的 入口点,可以从document开始去访问任何节点元素;

对于最顶层的html、head、body元素,我们可以直接在document对象中获取到:

  • html元素: = document.documentElement
  • body元素: = document.body
  • head元素: = document.head
  • 文档声明: = document.doctype

三、节点、元素导航

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

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

节点之间存在如下的关系:

  • 父节点:parentNode
  • 前兄弟节点:previousSibling
  • 后兄弟节点:nextSibling
  • 子节点:childNodes
  • 第一个子节点:firstChild
  • 最后一个子节点:lastChild

JavaScript的DOM操作(一)_第3张图片

// 1.获取节点的导航
var bodyEl = document.body
// 1.1.获取body所有的子节点
// console.log(bodyEl.childNodes)
// 1.2.获取body的第一个子节点
var bodyElFirstChild = bodyEl.firstChild
// 1.3.获取body中的注释
var bodyElCommentChild = bodyElFirstChild.nextSibling
console.log(bodyElCommentChild)
// 1.4.获取body的父节点
var bodyParent = bodyEl.parentNode
console.log(bodyParent)

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

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

节点之间存在如下的关系:

  • 父元素:parentElement
  • 前兄弟元素:previousElementSibling
  • 后兄弟元素:nextElementSibling
  • 子元素:children
  • 第一个子元素:firstElementChild
  • 最后一个子元素:lastElementChild

JavaScript的DOM操作(一)_第4张图片

var bodyEl = document.body
// 根据body元素去获取子元素(element)
var childElements = bodyEl.children
console.log(childElements)

// 获取box元素
var boxEl1 = bodyEl.firstElementChild
var boxEl2 = bodyEl.children[0]
console.log(boxEl1, boxEl2, boxEl1 === boxEl2)

// 获取ul元素
var ulEl = boxEl1.nextElementSibling
console.log(ulEl)

// 获取li元素
var liEls = ulEl.children
console.log(liEls)

3.表格(table)元素的导航

元素支持 (除了上面给出的,之外) 以下这些属性:

  • table.rows —

元素的集合;

  • table.caption/tHead/tFoot — 引用元素

  • table.tBodies —

  • 元素的集合;

    元素提供了 rows 属性:

    • tbody.rows — 表格内部 元素的集合;

    • tr.cells — 在给定

    中的 在封闭的 // 中的位置(索引);

  • tr.rowIndex — 在整个表格中

  • 的编号(包括表格的所有行);

    中单元格的编号。
    
      <table>
        <thead>
          <tr>
            <th>姓名th>
            <th>年龄th>
            <th>身高th>
          tr>
        thead>
        <tbody>
          <tr>
            <td>codertd>
            <td>18td>
            <td>1.88td>
          tr>
          <tr>
            <td>kobetd>
            <td>30td>
            <td>1.98td>
          tr>
        tbody>
      table>
    
      <script>
    
        var tableEl = document.body.firstElementChild
    
        // 通过table元素获取内部的后代元素
        // console.log(tableEl.tHead, tableEl.tBodies, tableEl.tFoot)
        // console.log(tableEl.rows)
    
        // 拿到一行元素
        // var rowEl = tableEl.rows[2]
        // console.log(rowEl.cells[0])
        // console.log(rowEl.sectionRowIndex)
        // console.log(rowEl.rowIndex)
    
      script>
    

    四、获取元素的方法

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

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

    DOM为我们提供了获取元素的方法:

    JavaScript的DOM操作(一)_第5张图片

    开发中如何选择呢?

    • 目前最常用的是querySelectorquerySelectAll
    • getElementById偶尔也会使用或者在适配一些低版本浏览器时;

    五、Node节点的属性

    1.节点的属性 - nodeType

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

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

    nodeType属性

    • nodeType 属性提供了一种获取节点类型的方法;
    • 它有一个数值型值(numeric value);

    常见的节点类型有如下:

    JavaScript的DOM操作(一)_第6张图片

    其他类型可以查看MDN文档: https://developer.mozilla.org/zh-CN/docs/Web/API/Node/nodeType

    // 1.获取三个节点
    var bodyChildNodes = document.body.childNodes
    var commentNode = bodyChildNodes[1]
    var textNode = bodyChildNodes[2]
    var divNode = bodyChildNodes[3]
    
    // 2.节点属性
    // 2.1.nodeType 节点的类型
    for (var node of bodyChildNodes) {
        if (node.nodeType === 8) {
        } else if (node.nodeType === 3) {
        } else if (node.nodeType === 1) {
        }
    }
    console.log(commentNode.nodeType, textNode.nodeType, divNode.nodeType) // 8 3 1
    console.log(Node.COMMENT_NODE)
    

    2.节点的属性 – nodeName、tagName

    nodeName:获取node节点的名字;

    tagName:获取元素的标签名词;

    tagName 和 nodeName 之间有什么不同呢?

    • tagName 属性仅适用于 Element 节点;
    • nodeName 是为任意 Node 定义的:
      • 对于元素,它的意义与 tagName 相同,所以使用哪一个都是可以的;
      • 对于其他节点类型(text,comment 等),它拥有一个对应节点类型的字符串;
    // 2.2.nodeName 节点的名称
    // tagName: 针对元素(element)
    // #comment #text string
    console.log(commentNode.nodeName, textNode.nodeName, typeof divNode.nodeName);
    // undefined undefined 'string'
    console.log(commentNode.tagName, textNode.tagName, typeof divNode.tagName);
    

    3.节点的属性 - innerHTML、textContent

    innerHTML 属性

    • 将元素中的 HTML 获取为字符串形式;
    • 设置元素中的内容;

    outerHTML 属性

    • 包含了元素的完整 HTML
    • innerHTML 加上元素本身一样;

    textContent 属性

    • 仅仅获取元素中的文本内容;

    innerHTML和textContent的区别:

    • 使用 innerHTML,我们将其“作为 HTML”插入,带有所有 HTML 标签。
    • 使用 textContent,我们将其“作为文本”插入,所有符号(symbol)均按字面意义处理。
    divNode.innerHTML;//hhhhei
    divNode.outerHTML;
    /*
    
    hhhhei
    */
    divNode.textContent;//hhhhei

    4.节点的属性 - nodeValue

    nodeValue/data

    • 用于获取非元素节点的文本内容
    // 获取注释
    console.log(commentNode.nodeValue);
    

    5.节点的其他属性

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

    DOM 元素还有其他属性:

    • value
    单元格的集合;

  • tr.sectionRowIndex — 给定的

    • td.cellIndex — 在封闭的