前端三基石(三) JavaScript DOM 操作与事件处理

📅 2026/7/21 19:59:37 👁️ 阅读次数 📝 编程学习
前端三基石(三) JavaScript DOM 操作与事件处理

目录

  • 前言
  • 一、DOM 是什么?
  • 二、获取元素
    • 2.1 传统方法
    • 2.2 选择器方法(推荐)
  • 三、操作元素内容
    • 3.1 innerHTML
    • 3.2 textContent vs innerText
  • 四、操作元素属性
    • 4.1 标准属性
    • 4.2 自定义属性
  • 五、操作元素样式
    • 5.1 style 属性
    • 5.2 classList(推荐)
  • 六、动态创建与删除元素
    • 6.1 创建元素
    • 6.2 添加元素
    • 6.3 删除元素
  • 七、事件处理
    • 7.1 事件绑定方式
    • 7.2 常用事件
    • 7.3 事件对象
    • 7.4 事件委托
  • 八、总结

前言

在上一篇中,我们掌握了 JavaScript 的核心语法——变量、函数、对象、运算符等。但学会语法只是第一步,JavaScript 在浏览器中的真正威力在于:操作网页元素、响应用户交互

这需要理解 DOM(Document Object Model)——浏览器提供给 JS 操作网页的接口。

本文是"前端三基石"系列第二篇的续篇,聚焦 DOM 操作与事件处理。


一、DOM 是什么?

DOM 是浏览器将 HTML 解析成的一棵节点树

<html><head><title>示例</title></head><body><divid="container"><pclass="text">Hello</p></div></body></html>

浏览器会将其解析为:

Document └── html ├── head │ └── title └── body └── div#container └── p.text └── "Hello"

每个 HTML 标签都是一个元素节点,文本内容是文本节点。JS 通过document对象访问这棵树。

后端类比:DOM 类似于 Java 解析 XML 的 DOM 模型——把文档结构化为对象树,通过 API 增删改查节点。


二、获取元素

操作元素的第一步是"找到它"。

2.1 传统方法

// 通过 id 获取(唯一)document.getElementById('container');// 通过标签名获取(返回集合)document.getElementsByTagName('div');// 通过类名获取(返回集合)document.getElementsByClassName('text');

这些方法返回的是HTMLCollection,是"活的"集合——文档变化时自动更新。

2.2 选择器方法(推荐)

ES5 提供了更灵活的选择器方法:

// 获取单个元素(第一个匹配的)document.querySelector('#container');document.querySelector('.text');document.querySelector('div p');// 获取所有匹配的元素(返回 NodeList)document.querySelectorAll('.text');document.querySelectorAll('div p');
方法返回值特点
querySelector()单个元素找不到返回null
querySelectorAll()NodeList找不到返回空列表(不是null

推荐使用选择器方法:语法统一(与 CSS 选择器一致),代码更清晰。


三、操作元素内容

3.1 innerHTML

读取或设置元素的 HTML 内容:

<divid="box"><span>Hello</span></div><script>constbox=document.getElementById('box');// 读取(得到 HTML 字符串)console.log(box.innerHTML);// "\n <span>Hello</span>\n"// 设置(会解析 HTML)box.innerHTML='<strong>World</strong>';</script>

安全警告:不要将用户输入直接赋值给innerHTML,会导致 XSS 攻击:

// 危险!用户输入可能包含恶意脚本box.innerHTML=userInput;// ❌// 安全的方式:使用 textContentbox.textContent=userInput;// ✅

3.2 textContent vs innerText

两者都操作纯文本,但有区别:

<divid="box"style="display:none">Hello<span>World</span></div><script>constbox=document.getElementById('box');console.log(box.textContent);// "Hello World"(获取所有文本)console.log(box.innerText);// ""(考虑 CSS 样式,隐藏元素返回空)</script>
属性特点性能
textContent获取所有文本,不考虑 CSS更快
innerText考虑 CSS 样式(如display: none较慢

推荐使用textContent,除非你需要考虑 CSS 样式。


四、操作元素属性

4.1 标准属性

对于 HTML 标准属性(如idclassNamehrefsrc),可以直接访问:

constlink=document.querySelector('a');// 读取console.log(link.href);console.log(link.id);// 设置link.href='https://example.com';link.id='newId';// 特殊:class 要用 className(因为 class 是 JS 保留字)element.className='active';

4.2 自定义属性

HTML5 允许使用data-*自定义属性:

<divid="box"data-user-id="123"data-role="admin"></div><script>constbox=document.getElementById('box');// 读取console.log(box.dataset.userId);// "123"(自动转为驼峰)console.log(box.dataset.role);// "admin"// 设置box.dataset.userId='456';</script>

也可以使用通用方法:

// 任意属性都可用element.getAttribute('data-user-id');element.setAttribute('data-user-id','789');element.removeAttribute('data-user-id');

五、操作元素样式

5.1 style 属性

直接修改内联样式:

constbox=document.getElementById('box');box.style.width='100px';box.style.height='50px';box.style.backgroundColor='red';// 注意:用驼峰命名box.style.display='none';

缺点

  • 只能设置内联样式,无法操作 CSS 类
  • 样式名需要转为驼峰(background-colorbackgroundColor

5.2 classList(推荐)

通过操作 CSS 类来控制样式:

<style>.active{background-color:red;}.hidden{display:none;}</style><divid="box">Hello</div><script>constbox=document.getElementById('box');// 添加类box.classList.add('active');// 移除类box.classList.remove('active');// 切换类(有则移除,无则添加)box.classList.toggle('hidden');// 判断是否包含类if(box.classList.contains('active')){console.log('box 是激活状态');}</script>
方法作用
add()添加类
remove()移除类
toggle()切换类
contains()判断是否包含
replace(old, new)替换类

推荐使用classList:样式与行为分离,易于维护。


六、动态创建与删除元素

6.1 创建元素

// 创建元素constdiv=document.createElement('div');// 设置属性和内容div.id='newDiv';div.className='box';div.textContent='新创建的元素';// 或使用 innerHTMLdiv.innerHTML='<span>内容</span>';

6.2 添加元素

<divid="container"><pid="first">第一段</p></div><script>constcontainer=document.getElementById('container');constnewDiv=document.createElement('div');newDiv.textContent='新元素';// 追加到末尾container.appendChild(newDiv);// 插入到指定元素之前constfirst=document.getElementById('first');container.insertBefore(newDiv,first);// 新方法(更直观)container.append(newDiv);// 末尾添加container.prepend(newDiv);// 开头添加first.before(newDiv);// 在 first 之前插入first.after(newDiv);// 在 first 之后插入</script>

6.3 删除元素

constbox=document.getElementById('box');// 传统方法box.parentNode.removeChild(box);// 新方法(推荐)box.remove();

七、事件处理

7.1 事件绑定方式

方式一:HTML 属性(不推荐)

<buttononclick="alert('点击了')">点击</button>

缺点:HTML 与 JS 混在一起,难以维护。

方式二:DOM 属性

constbtn=document.getElementById('btn');btn.onclick=function(){alert('点击了');};// 缺点:只能绑定一个处理函数,后绑定的会覆盖前面的

方式三:addEventListener(推荐)

constbtn=document.getElementById('btn');btn.addEventListener('click',function(){alert('点击了');});// 优点:可以绑定多个处理函数btn.addEventListener('click',function(){console.log('另一个处理函数');});// 移除事件(需要保持同一个函数引用)functionhandleClick(){console.log('点击');}btn.addEventListener('click',handleClick);btn.removeEventListener('click',handleClick);

7.2 常用事件

事件触发时机
click点击
dblclick双击
mouseenter鼠标进入
mouseleave鼠标离开
keydown键盘按下
keyup键盘抬起
focus获得焦点
blur失去焦点
input输入内容变化(实时)
change值改变并失焦
submit表单提交
load资源加载完成
DOMContentLoadedDOM 解析完成

示例:

// 输入框实时响应constinput=document.querySelector('input');input.addEventListener('input',function(){console.log('当前值:',this.value);});// 表单提交constform=document.querySelector('form');form.addEventListener('submit',function(e){e.preventDefault();// 阻止默认提交行为console.log('表单数据:',newFormData(this));});

7.3 事件对象

事件处理函数会收到一个事件对象:

btn.addEventListener('click',function(e){console.log(e.target);// 触发事件的元素(实际点击的)console.log(e.currentTarget);// 绑定事件的元素(this 指向它)console.log(e.type);// 事件类型console.log(e.clientX,e.clientY);// 鼠标坐标e.preventDefault();// 阻止默认行为e.stopPropagation();// 阻止冒泡});

target vs currentTarget

<ulid="list"><li>项目1</li><li>项目2</li></ul><script>constlist=document.getElementById('list');list.addEventListener('click',function(e){console.log(e.target);// 实际点击的 liconsole.log(e.currentTarget);// ul});</script>

7.4 事件委托

问题:动态添加的元素没有事件绑定

// 只对已有的 li 生效,新添加的没有事件document.querySelectorAll('li').forEach(li=>{li.addEventListener('click',function(){console.log(this.textContent);});});

解决:事件委托——将事件绑定到父元素,利用冒泡机制

constlist=document.getElementById('list');list.addEventListener('click',function(e){// 判断点击的是否是 liif(e.target.tagName==='LI'){console.log(e.target.textContent);}});

优点

  • 动态元素也有事件
  • 代码更简洁,内存占用更少

八、总结

类别内容推荐方法
获取元素选择元素querySelector/querySelectorAll
操作内容读写文本/HTMLtextContent/innerHTML(注意安全)
操作属性标准属性/自定义属性直接访问 /dataset
操作样式控制样式classList
创建元素动态生成元素createElement+append
删除元素移除元素remove()
事件绑定响应用户操作addEventListener
事件优化动态元素事件事件委托

核心记忆点

  1. 用选择器方法获取元素
  2. classList操作样式
  3. addEventListener绑定事件
  4. 动态元素用事件委托

本文是"前端三基石"系列第二篇的续篇。下一篇将讲解异步编程与网络请求。