Skip to content

DOM 与事件

JavaScript 基础篇介绍了变量、条件、循环、函数。但那些代码跑在 Console 里,跟页面没关系。JS 怎么改页面上的标题、怎么知道用户点了按钮、怎么读输入框里的值?这就需要 DOM。

DOM(Document Object Model)是浏览器把 HTML 解析后生成的页面对象树。JS 通过 DOM 读取元素、修改内容、监听事件——这就是"页面交互"的本质。

一、查找元素

document.querySelector 用 CSS 选择器找元素——跟 CSS 选择器写法一样,#title 按 id 找,.note 按 class 找:

html
<h1 id="page-title">文章管理</h1>
<p class="desc">第一段说明。</p>
<p class="desc">第二段说明。</p>
js
const title = document.querySelector("#page-title");     // 找第一个匹配
const firstDesc = document.querySelector(".desc");       // 找第一个 class=desc
const allDescs = document.querySelectorAll(".desc");     // 找全部 class=desc

console.log(title.textContent);   // 文章管理
console.log(allDescs.length);     // 2

querySelector 返回第一个匹配的元素(没找到返回 null),querySelectorAll 返回所有匹配的元素列表。JS 执行时 HTML 必须已经加载完——所以 <script> 放在 <body> 末尾,不然元素还没出来就去找,返回 null

二、修改内容

改文字用 textContent,改 HTML 用 innerHTML

js
const title = document.querySelector("#page-title");
title.textContent = "新标题";        // 纯文本

const box = document.querySelector("#box");
box.innerHTML = "<strong>加粗内容</strong>";  // 会解析成 HTML

显示外部输入时优先用 textContent——innerHTML 会把字符串里的标签当成真实 HTML 执行,如果内容来自用户输入,可能被注入恶意代码。

改样式和 class:

js
const box = document.querySelector(".card");

box.classList.add("active");       // 加 class
box.classList.remove("hidden");    // 删 class
box.classList.toggle("selected");  // 有就删,没有就加

classList 比直接拼 className 更安全——不会把原有的 class 覆盖掉。

改属性(比如链接地址、输入框值):

js
const link = document.querySelector("a");
link.href = "https://example.com";

const input = document.querySelector("input");
input.value = "预设值";           // 读输入框值也是 input.value

三、创建元素

页面上的列表内容经常是动态的——从数据生成。document.createElement 创建新元素,appendChild 挂到父元素上:

html
<ul id="article-list"></ul>
js
const list = document.querySelector("#article-list");

const articles = ["Python 入门", "Go 并发", "Rust 安全"];

// 先清空旧内容
list.innerHTML = "";

// 逐条创建列表项
for (const title of articles) {
  const item = document.createElement("li");
  item.textContent = title;
  list.appendChild(item);
}

list.innerHTML = "" 清空旧内容——重新渲染列表前的标准操作。

四、事件

事件表示页面上发生了动作——点击、输入、提交。addEventListener 监听事件:

html
<button id="btn" type="button">点击</button>
<p id="msg"></p>
js
const button = document.querySelector("#btn");
const msg = document.querySelector("#msg");

button.addEventListener("click", () => {
  msg.textContent = "按钮被点了";
});

addEventListener("click", 回调函数)——用户点击时,浏览器调回调函数。常见事件:click(点击元素)、input(输入框内容变化,每打一个字触发)、change(输入框失焦或选择变化时触发)、submit(表单提交)、keydown(键盘按下)。

实时预览输入内容:

html
<input id="title-input" type="text">
<p id="preview"></p>
js
const input = document.querySelector("#title-input");
const preview = document.querySelector("#preview");

input.addEventListener("input", () => {
  preview.textContent = input.value;   // 每打一个字就更新预览
});

input.value 读输入框当前值。input 事件每打一个字触发一次——搜索框实时筛选、表单实时校验都用它。

五、表单处理

表单默认提交会刷新页面(浏览器按 action 跳转)。用 JS 处理表单时,先阻止默认提交,再读取字段

html
<form id="article-form">
  <label for="title">标题</label>
  <input id="title" name="title" type="text" required>

  <label for="category">分类</label>
  <select id="category" name="category">
    <option value="tech">技术</option>
    <option value="life">生活</option>
  </select>

  <button type="submit">提交</button>
</form>

<pre id="result"></pre>
js
const form = document.querySelector("#article-form");
const result = document.querySelector("#result");

form.addEventListener("submit", (event) => {
  event.preventDefault();     // 阻止页面刷新

  // FormData 按 name 收集所有字段值
  const formData = new FormData(form);
  const data = Object.fromEntries(formData.entries());

  result.textContent = JSON.stringify(data, null, 2);
});

event.preventDefault() 是关键——不写的话表单提交后页面直接刷新,JS 代码来不及执行。FormData 按字段的 name 属性收集值,输入框缺 name 时数据里不会有这个字段

六、完整示例:文章列表

把 DOM 操作和事件合到一个页面:从内存数据渲染文章列表,表单新增文章后实时更新页面。这个例子不调后端 API——数据只存在浏览器内存里,刷新会丢。调 API 是下一篇(异步与网络请求)的事。

文件:index.html

html
<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <title>文章管理</title>
  </head>
  <body>
    <h1>文章管理</h1>

    <ul id="article-list"></ul>

    <form id="article-form">
      <label for="title">标题</label>
      <input id="title" name="title" type="text" required>

      <label for="category">分类</label>
      <select id="category" name="category">
        <option value="tech">技术</option>
        <option value="life">生活</option>
      </select>

      <button type="submit">新增</button>
    </form>

    <script src="app.js"></script>
  </body>
</html>

文件:app.js

js
// 初始数据(存在内存里,刷新会丢)
let articles = [
  { title: "Python 入门", category: "tech" },
  { title: "读书笔记", category: "life" },
];

const list = document.querySelector("#article-list");
const form = document.querySelector("#article-form");

// 渲染列表
function renderArticles() {
  list.innerHTML = "";   // 先清空

  for (const article of articles) {
    const item = document.createElement("li");
    item.textContent = `${article.title}(${article.category})`;
    list.appendChild(item);
  }
}

// 表单提交:新增文章
form.addEventListener("submit", (event) => {
  event.preventDefault();

  const formData = new FormData(form);
  const data = Object.fromEntries(formData.entries());

  articles.push(data);   // 加到数组末尾
  form.reset();          // 清空表单
  renderArticles();      // 重新渲染
});

// 页面加载后先渲染一次
renderArticles();

打开页面看到两篇文章。在表单里填一篇新的,点新增——列表立刻多了一条。整个过程不刷新页面、不调后端,纯靠 DOM 操作。这就是"前端交互"的基本形态。

七、常见问题

现象常见原因排查入口
元素读不到(返回 null)JS 执行时 HTML 还没加载,或选择器写错<script> 放 body 末尾、Console 查选择器
表单提交后页面刷新没调 event.preventDefault()submit 事件处理
字段没进 FormData输入框缺 name 属性表单 HTML
点击没反应事件名写错(onClick vs click)或元素没找到Console 看有没有报错

DOM 问题看 Elements 和 Console,请求问题看 Network——F12 打开开发者工具,这三个面板覆盖了前端排查 90% 的场景。