🐸 青蛙编程网
首页 / 前端 / JavaScript / 4. 操作网页:DOM

操作网页:DOM

这是什么:DOM(Document Object Model,文档对象模型)= 浏览器把 HTML 解析成的对象树,document 是它的入口。

为什么用:前三章我们都在 F12 控制台"练内功"。现在让 JS 走出控制台,真正动手改网页——这是前端最有成就感的时刻。

如何用:用 document.querySelector('#msg') 找到元素,在页面里点「▶ 运行」看文字和样式被改掉。

什么是 DOM

浏览器会把 HTML 解析成一棵对象树,这棵树叫 DOM(Document Object Model,文档对象模型)。在 JS 眼里,每个标签都是一个对象,而 document 就是整棵树的入口——想改谁,先从 document 出发找到它。

找到元素:两种方式

document.getElementById('msg')    // 按 id 精确查找,返回一个元素
document.querySelector('#msg')    // 按 CSS 选择器查找:#id、.类名、标签名都行
document.querySelector('.box')    // 第一个 class 为 box 的元素

「你会看到」:在控制台输入会返回找到的元素对象;没找到则是 null。两种都常用,本书统一用更灵活的 querySelector。

改文字、改样式

let box = document.querySelector('#msg')
box.textContent = '文字被 JS 换掉了'   // 改内容
box.style.color = 'tomato'             // 改样式:style.属性名 = 值
box.style.fontSize = '24px'            // CSS 的 font-size,在 JS 里写成 fontSize

「你会看到」id 为 msg 的元素文字变了、变红、变大。注意:CSS 的连字符写法(font-size)到 JS 里要改成驼峰(fontSize)。

代码 作用
document.querySelector('#msg') 从整棵 DOM 树里找到目标元素
textContent 读 / 改元素的文字内容
style.xxx 改内联样式

完整示例:点按钮改文字

下面是 HTML + JS 的组合拳,直接点「▶ 运行」体验,也可以改改代码再运行:

🧪 在线运行
👀 运行结果

💡 代码可直接复制;想改、想跑,点右上「🧪 在线运行场」。

逐段解读:

代码 作用
<p id='msg'> 给段落一个 id,方便 JS 找到它
onclick='changeText()' 点击按钮时调用 changeText 函数
querySelector('#msg') 找到那个段落
box.textContent = ... 换掉文字
box.style.color = ... 顺手改个颜色

记忆口诀:先找到,再动手——querySelector 找元素,textContent 改字,style 改样。

❓ 常见问题

Q1:点按钮报 TypeError: Cannot set properties of null (setting 'textContent')?

原因:querySelector 没找到元素,返回了 null,后面 box.textContent = ... 就是在给 null 改属性——null 身上什么都没有,浏览器当场拒绝。

TypeError: Cannot set properties of null (setting 'textContent')

修复三步:① 先把 querySelector('#msg') 那行在控制台单独跑一下,看是不是返回 null;② 是 null 就核对选择器拼写:#msg 的 # 写了没、id 一个字母没拼错;③ 改对后返回的是元素对象,报错消失。 举一反三:见到 Cannot set properties of null,百分百是"上一步没找到东西"——别急着改赋值那行,先回头查查找那行。

Q2:写 document.querySelector('msg') 也报同样的 null 错?

原因:少了 #。选择器用的是 CSS 语法:#msg 表示 id、.box 表示 class、p 表示标签;光写 msg 是在找 <msg> 标签,页面上当然没有。

null

修复三步:① 回看 HTML 里目标元素是靠 id 还是 class 标识的;② id 前面补 #,class 前面补 .;③ 在控制台跑一下确认返回元素而不是 null。 举一反三:选择器就是 CSS 选择器——你在样式表里怎么写,querySelector 里就怎么写,一条规则两边通用。

Q3:写 box.style.font-size = '24px' 报 SyntaxError: Invalid left-hand side in assignment?

原因:JS 里 - 是减号!font-size 被理解成 font 减 size,而减法结果不能被赋值,语法检查直接拦下。

SyntaxError: Invalid left-hand side in assignment

修复三步:① 跳到报错行;② 把连字符改成驼峰:fontSize、backgroundColor;③ 记住换算规则:background-color → backgroundColor,去掉横线、第二个单词首字母大写。 举一反三:凡是 CSS 属性带横线的,到 JS 的 style 里全部转驼峰,一条规则包打天下。

Q4:document.getElementById('#msg') 返回 null,明明 id 就叫 msg?

原因:这两个函数"口味"不同——querySelector 吃 CSS 选择器要带 #;getElementById 吃裸 id,不带 #。写成 getElementById('#msg'),它在找 id 字面上叫 #msg 的元素,当然找不到。 修复三步:① 确认自己在用哪个函数;② getElementById('msg') 去掉井号,或改用 querySelector('#msg') 保留井号;③ 两选一后别混搭。 举一反三:容易忘就统一用 querySelector,一套选择器语法走到底,不用记两套规矩。

Q5:代码一字不差,为什么还是 Cannot set properties of null?

原因:多半是 <script> 写在了目标元素前面——浏览器从上往下执行,脚本跑到时元素还没出生,自然找不到。 修复三步:① 检查 <script> 的位置;② 把它挪到目标元素的后面(比如 </body> 前);③ 刷新页面重试。 举一反三:JS 是按顺序执行的"流水线",想操作谁,得等它先出现——"先找到,再动手"还包括"先出生,再找到"。

⚠️ 新手翻车现场

翻车一:选择器忘了 #,元素人间蒸发

let box = document.querySelector('msg')
box.textContent = '我被改了'

完整报错:

TypeError: Cannot set properties of null (setting 'textContent')

逐行分析:错在第 1 行——'msg' 没带 #,querySelector 去找 <msg> 标签,页面上没有这个标签,返回 null。第 2 行给 null 改文字,报 TypeError。病灶在第 1 行,案发现场在第 2 行——报错行号指向赋值处,但根子在上面的查找处。

正确写法:

let box = document.querySelector('#msg')
box.textContent = '我被改了'

翻车二:CSS 的横线直接搬进 JS

let title = document.querySelector('#title')
title.style.background-color = 'lightyellow'

完整报错:

SyntaxError: Invalid left-hand side in assignment

逐行分析:错在第 2 行的 background-color——JS 把 - 读成减号,整句变成"背景色减去 color 再赋值",语法不合法,还没运行就被拦住。CSS 的横线命名到了 JS 里必须换成驼峰。

正确写法:

let title = document.querySelector('#title')
title.style.backgroundColor = 'lightyellow'

翻车三:id 手滑打错一个字母

<p id='msg'>我是一段普通的文字</p>
let box = document.querySelector('#msge')
box.textContent = '我被改了'

完整报错:

TypeError: Cannot set properties of null (setting 'textContent')

逐行分析:HTML 里 id 是 msg,JS 里却写成了 #msge——多个 e,天涯之别。querySelector 找不到 id 为 msge 的元素,返回 null,第 2 行随之上演熟悉的 TypeError。HTML 和 JS 两边的名字必须一字不差,复制粘贴比手打靠谱。

正确写法:

let box = document.querySelector('#msg')
box.textContent = '我被改了'

📦 完整小示例

给"青蛙茶铺"做个促销按钮:点一下,标题和价格牌同时换装——两个元素一次改到位:

<h2 id='title'>今日茶饮</h2>
<p id='price'>荷叶茶 原价 20 元</p>
<button onclick='startSale()'>点击开始促销</button>
<script>
  function startSale() {
    let title = document.querySelector('#title')
    let price = document.querySelector('#price')
    title.textContent = '限时特卖进行中!'
    title.style.color = 'tomato'
    price.textContent = '荷叶茶 直降 8 元,现价 12 元!'
    price.style.backgroundColor = 'lightyellow'
    price.style.fontSize = '20px'
  }
</script>

你会看到:页面初始是普通的"今日茶饮"和一行价格;点击按钮后——标题变成红色大字"限时特卖进行中!",价格那行套上了淡黄色背景、字号变大,写着"荷叶茶 直降 8 元,现价 12 元!"。

逐段中文精讲

  • 第 1~2 行(准备两块牌子):标题 <h2> 和价格 <p> 各自领了 id——想被 JS 找到,先挂好"门牌号"。
  • 第 3 行(按钮接线):onclick='startSale()' 把按钮和函数接在一起:点一下,函数跑一遍。
  • 第 6~7 行(先找到):两行 querySelector 分头把两个元素逮住,存进 title 和 price 两个变量——要改几个元素,就先抓几个。
  • 第 8~9 行(改标题):textContent 换字,style.color 上色——每个属性一行,分工明确。
  • 第 10~12 行(改价格牌):换内容、铺背景、调字号三连;注意 backgroundColor 和 fontSize 都是驼峰写法,CSS 里的 background-color、font-size 在这里全部改头换面。

跑通后做个小实验:再加一行 title.style.fontSize = '32px',让标题也变大;或者给按钮加个 id,点完促销后再写个函数把价格改回去——一去一回,你就做了个"促销开关"。

🎯 什么时候用它

  • 购物车小计实时更新:每点一次"加入购物车",JS 就找到页面上显示合计的那个元素,把 textContent 改成新总价——你看到的每个实时变动的数字背后都是这一招。
  • 表单提交后的提示:点"提交"后,把提示区域的文字改成"保存成功 ✓"、颜色改成绿色——比弹窗温柔,用户体验更好。
  • 深浅色主题切换:点切换按钮,JS 把 body 的 backgroundColor、各文字的 color 一起改掉——所谓"换肤",本质就是一批 style 修改。

📝 本章小结

  • 浏览器把 HTML 解析成 DOM 对象树,document 是入口:想改谁,先找到谁。
  • querySelector('#id') 按 CSS 选择器找元素;找不到返回 null——注意 # 别丢。
  • textContent 改文字,style.属性名 改样式;CSS 的横线写法到 JS 要转驼峰(font-size → fontSize)。
  • Cannot set properties of null = 上一步没找到元素,回头查选择器和 script 位置。
  • 记忆锚点:DOM 像一棵挂满礼物的圣诞树,id 是礼物上的名牌;querySelector 负责"按名牌找礼物",textContent 和 style 负责"换字换色"。

动手改

  1. 把 textContent 的内容换成你的名字,运行后点按钮看看
  2. 把颜色改成 'dodgerblue',再加一行 box.style.backgroundColor = 'lightyellow'
  3. 加第二个按钮,点击后把文字改回"我是一段普通的文字"

下一章:事件,让网页听懂用户的每一个动作 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。