操作网页: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 负责"换字换色"。
动手改
- 把 textContent 的内容换成你的名字,运行后点按钮看看
- 把颜色改成 'dodgerblue',再加一行
box.style.backgroundColor = 'lightyellow' - 加第二个按钮,点击后把文字改回"我是一段普通的文字"
下一章:事件,让网页听懂用户的每一个动作 🐸