# 找到那个 DOM

# 课程目标

JavaScript 最独特和最有用的能力之一是它能够操纵 DOM,从而实现与您的 HTML 交互以创建交互式用户体验

那么什么是 DOM,我们如何去改变它呢?我们将分几节课学习 DOM 的相关知识,本节我们先学习如何定位 DOM 元素

# DOM 的定义和基本概念

DOM(文档对象模型)是 HTML 和 XML 文档的编程接口。DOM 表示由多层节点构成的文档,通过它开发者可以与页面上的元素进行交互,您可以阅读和更改文本、添加和删页面各个部分

# 选择 DOM 节点

接下我们学习如何定位 DOM 节点,比如你想找到 id 为 header 的<div>节点,或者找到页面中所有的链接

# document.querySelector

为了能够操作 DOM 中的元素,您必须选择该特定元素,您可以使用以下 document.querySelector 方法从页面中选择单个 DOM 节点:

document.querySelector("CSS 选择器");

querySelector 方法需要一个 CSS 选择器,这与您在 CSS 文件中编写的选择器相同。

如果有多个项目满足您指定的 CSS 选择器,则只返回第一个。

# document.querySelectorAll()

但是,如果您需要查找 1 个以上的元素怎么办?如果需要返回所有匹配的元素"CSS-selector"怎么办?

这种场景下,您需要使用 document.querySelectorAll().

# 常见选择器

让我们来看看一些最常见的选择器:

类型选择器

<form>This is a form</form>
<script>
  const form = document.querySelector("form");
</script>

ID 选择器

<div id="sidebar"></div>
<script>
  const sidebar = document.querySelector("#sidebar");
</script>

类选择器

<div class="active"></div>
<script>
  const item = document.querySelector(".active");
</script>

后代选择器

<ul>
  <li></li>
</ul>
<script>
  const item = document.querySelector("ul li");
</script>

属性选择器

<input type="text" placeholder="Your name here" disabled />
<script>
  document.querySelector("[disabled]");
</script>

更多的 CSS 选择器,请参考Selectors | W3C (opens new window)

如果您想在有趣的游戏中练习 CSS 选择器,请查看flukeout.github.io (opens new window)

# 其他查找 DOM 节点方法

本课程的建议是,您始终可以使用 querySelector 而不是 getElementById ,而且,因为 querySelector 适用于所有场景,可以避免混淆是否应该添加#。

# 节点列表(nodeList)

一个节点列表是 DOM 元素的集合。这意味着它是一个包含多个 DOM 元素的变量。

该节点列表对象类似于数组,但它不是一个数组

# 将节点列表转换为数组

我们知道 NodeList 是类数组 只支持.length, .forEach(),但是如果出于某种原因你想使用.map()或者.filter()呢?

为了能够做到这一点,您必须将 NodeList 转换为一个数组。

const divs = document.querySelectorAll("div"); // NodeList
const items = [...divs]; // Array

如您所见,您可以使用数组展开语法 ( ...)将 NodeList 转换为数组,该语法将 NodeList 的每一项展开为一个新数组。

还有一种方法是可以使用 Array.from()将结点集合转换为数组

const divs = document.querySelectorAll("div"); // NodeList
Array.from(document.body.divs); // Array

# Traversing 遍历 DOM 树

在本课中,您将学习如何遍历 DOM。例如,如何到达父元素以及如何找到与某个选择器匹配的“最近”(搜索父元素)元素。

# 寻找父节点

# element.parentElement

element.parentElement 属性返回当前元素的父元素

# element.closest("CSS 选择器")

# 任务一

请完成下列函数

// 获取当前element元素所有的兄弟节点
function getSiblings(element){
    // your implement
}

// 获取当前element元素前一个兄弟节点
function getPrev(element){
    // your implement
}

// 获取element元素之前所有的兄弟节点
function getPrevaAll((element){
    // your implement
}

// 获取element元素之后第一个兄弟节点
function getNext((element){
    // your implement
}

// 获取element元素之后所有的兄弟节点
function getNextAll((element){
    // your implement
}

// 获取元素的所有子节点
function getSon(element){
   // your implement
}
//获取元素的第一个子节点
function getFirstSon(element){
   // your implement
}
/**
 * @descriotion 获取element的符号 parent_css_selector 的父元素
 * @param {object} element
 * @param {String} parent_css_selector 父元素的 css 选择器
 */
function getParent( element,parent_css_selector){
   // your implement
}
// 判断element的节点类型,并且返回
function getNodeType(element) {
    // your implement
}

// 获取element元素完整的HTML内容
function getHTMLContent(element) {
    // your implement
}
// 获取element元素的文本内容
function getText(element) {
    // your implement
}

# 任务二

基于我们给出的一个问卷调查页面,使用 querySelector 及 querySelectorAll 来实现如下 DOM 节点搜索要求

在一个单独的窗口中打开 survey.html (opens new window) 页面,并对此页面使用浏览器开发者工具。

  1. 完成对以下元素的查找
  • 带有 id="rate-table" 的表格。
  • 带有 name = "select-check: 的 fieldset。
  • 表格中的第一个 td (带有 "rate" 字段)
  • 表单中的第一个 input。
  • 表单中的最后一个 input。
  • 获取带有 data-widget-name 特性(attribute)的元素
  • 表单中 第二个 name = "dishes" 的单选框
  • 表单中 name 含有 pick 字段的元素
  • 带有 class = "check" 的元素集合
  1. 给所有的必填输入框添加一个绿色边框,请您将获取的输入框节点列表表转化为数组
element.style.border = "1px solid green";
  1. 对页面元素的遍历,编写代码给每一个遍历到的元素添加一个红色背景颜色
element.style.background = "1px solid green";

# 进阶任务

如果你很快就完成上面的任务,可以去 LeetCode 上去多进行一些练习。

# 提交

把你今天觉得做得最好的代码放在 Github 后进行提交。

# 总结

依然把今天的学习用时,收获,问题进行记录。

# 自测问题

  • DOM 树的最顶层元素是什么?
  • 下面这个脚本会显示什么?
<html>
  <body>
    <script>
      console.log(document.body.lastChild.nodeType);
    </script>
  </body>
</html>
  • document 属于哪一类?它位于 DOM 层次结构(hierarchy)中的什么位置?它继承自 Node 还是 Element,或者可能是 HTMLElement?
  • getComputedStyle(elem).width 与 elem.clientWidth 之间有什么不同点?指出至少三种不同点。当然越多越好。