跳至正文
来两杯美式
返回

前端核心(一):DOM 入门

By 来两杯美式
发布于

DOM 入门教程(面向 T3/React 开发者精简版)

本教程砍掉了所有过时、不常用的DOM知识点,只讲你后续学React/Next/T3必须理解的核心内容,不用死记硬背API,理解原理即可,90%的原生DOM操作后续都会被React封装,你只需要搞懂底层逻辑。


一、DOM 到底是什么?

DOM 全称 Document Object Model(文档对象模型),是浏览器把HTML字符串解析后,存在内存里的可被JS操作的树形对象结构

对应你之前问的根节点问题,DOM树的层级结构很清晰:

Document(整个文档的根对象,对应JS里的`document`)
└── <html> 元素(所有HTML标签的根节点,对应`document.documentElement`)
    ├── <head> 元素(对应`document.head`)
    │   ├── <title>、<meta>、<link>等元信息标签
    └── <body> 元素(对应`document.body`)
        ├── <div>、<h1>、<a>等业务内容标签

平时口头说的「根节点」默认指<html>标签,React项目里的「业务根节点」一般是你挂在<body>里的<div id="root">容器。


二、必须了解的3种DOM节点类型

不用记所有节点类型,只需要知道最常用的3种:

  1. 元素节点:所有HTML标签(div、p、button等),是你操作最多的节点类型
  2. 文本节点:标签里的文字内容,比如<p>你好</p>里的「你好」就是文本节点
  3. 属性节点:标签上的属性,比如<a href="xxx">里的href就是属性节点

其他注释节点、文档片段节点等了解即可,几乎不会直接操作。


三、实际开发常用的DOM操作(了解原理即可,不用背)

1. 查找元素(最常用,哪怕写React偶尔也会用到)

现在主流只用这几个API,其他老旧的getElementsByTagName等不用记:

API作用示例
document.getElementById('id名')按id找唯一元素document.getElementById('root')
document.querySelector('CSS选择器')按CSS选择器找第一个匹配的元素document.querySelector('.btn')
document.querySelectorAll('CSS选择器')找所有匹配的元素,返回NodeList类数组document.querySelectorAll('li')

注意:querySelectorAll返回的不是真数组,要转数组用Array.from(document.querySelectorAll('li'))或者[...document.querySelectorAll('li')]

2. 修改元素

修改内容

React默认所有渲染内容都会转义成纯文本,就是为了避免XSS风险,底层就是类似textContent的逻辑。

修改属性

修改样式

3. 增删节点(了解即可,React会帮你做)

// 新增节点
const div = document.createElement("div"); // 创建div元素
div.textContent = "我是新增的";
document.body.appendChild(div); // 把div加到body的最后

// 删除节点
div.remove(); // 直接删自己
// 或者父节点删子节点:document.body.removeChild(div)

四、核心重点:DOM 事件机制(必须彻底理解,原生/React都要用)

所有页面交互(点击、输入、滚动等)都是基于DOM事件实现的。

1. 事件绑定的正确方式

只用addEventListener即可,其他行内绑定、onclick属性绑定都不推荐:

const btn = document.querySelector(".btn");
// 第一个参数是事件名,第二个是触发事件的回调函数
btn.addEventListener("click", e => {
  console.log("按钮被点击了");
});

2. 事件对象e的常用属性/方法

回调函数里的e就是事件对象,常用的只有这几个:

3. 事件冒泡(必须理解)

事件触发后,会从触发的元素一层层往上传递到父元素,直到document根节点,这个就是冒泡。

举个例子:你点击了div里面的button,button的点击事件触发后,div的点击事件、body的点击事件也会依次触发。

如果不想让事件往上传,就在子元素的回调里加e.stopPropagation()

React的合成事件就是基于事件冒泡原理实现的,所有事件都绑定在根节点上,性能更高,你懂了原生冒泡才能理解React合成事件的逻辑。

4. 事件委托(了解原理)

利用冒泡的特性,给父元素绑定事件,就能处理所有子元素的事件,不用给每个子元素单独绑,性能更高。比如你有1000个列表项要绑点击事件,不用循环给每个li绑,直接给父ul绑事件,通过e.target判断点的是哪个li即可。


五、学DOM对T3/React开发的意义

你写T3项目的时候90%的场景都不会直接操作原生DOM,但是你必须懂DOM原理:

  1. 理解React的运行逻辑:React的虚拟DOM本质就是对原生DOM的模拟,你改state之后React会比对新旧虚拟DOM的差异,然后调用原生DOM API更新真实DOM,懂了原生DOM你才知道React为什么这么设计。
  2. 特殊场景要用:比如你用useRef获取真实DOM做滚动、聚焦、调用第三方依赖DOM的库的时候,你得知道拿到的DOM对象是什么、怎么操作。
  3. 排查问题:遇到事件冒泡冲突、样式异常、XSS风险等问题的时候,懂原生DOM才能快速定位根因。

六、小练习(10分钟就能做完,帮你巩固)

写一个静态HTML页面,实现:点击按钮切换文字的颜色,按钮文字在「开」「关」之间切换。

<!DOCTYPE html>
<html>
  <body>
    <p id="text">我是要变色的文字</p>
    <button id="btn"></button>
    <script>
      const text = document.getElementById("text");
      const btn = document.getElementById("btn");
      let isActive = false;
      btn.addEventListener("click", () => {
        isActive = !isActive;
        text.style.color = isActive ? "red" : "black";
        btn.textContent = isActive ? "" : "";
      });
    </script>
  </body>
</html>

做完之后你可以想一下:如果用React写这个功能,你会怎么写?对比一下原生和框架的差异,就能直观感受到框架帮你省了多少手动操作DOM的代码。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.前端核心(一):DOM 入门
  2. 02.前端核心(二):React 必备 JS 语法速查
  3. 03.前端核心(三):Promise 与异步编程详解
  4. 04.前端核心(四):React 必备 TS 语法速查

上一篇
前端核心(二):React 必备 JS 语法速查
下一篇
CSS 基础(七):响应式设计与媒体查询