JavaScript DOM 操作与事件处理全解析
内容概要:
本篇文章介绍了JavaScript DOM 中的基础概念和相关的操作。其中操作包括五种获取元素的方法、常见的事件机制(鼠标事件和键盘事件),以及对元素的相关操作:对元素内容的操作,对元素属性的操作,对表单元素的操作,对CSS样式的操作。还有大量的代码示例,和文字描述,文章的字数有14000字左右,花费了大量时间,欢迎大家一起学习和进步,最后大家喜欢的话给小宁留下关注和点赞哦!
引言:JavaScript 与网页交互的核心
在现代网页开发中,JavaScript 作为前端交互的灵魂,其与 HTML 文档的交互主要通过 DOM(Document Object Model)实现。DOM 不仅是浏览器对网页的内部表示,更是开发者通过代码操作页面的桥梁。本文将深入解析 DOM 文档对象模型、事件机制及元素操作的核心知识,帮助你掌握前端交互开发的关键技能。
1.1 什么是 DOM?
DOM(Document Object Model)是 HTML 和 XML 文档的编程接口,它将文档解析为一个由节点组成的树状结构,允许开发者通过 JavaScript 动态操作网页的内容、结构和样式。简单来说,DOM 就是浏览器对网页的一种 "对象化" 表示,就像将一本图书拆解成章节、段落、句子等层级结构,每个部分都可以被独立访问和修改。
DOM 的核心作用:
- 将 HTML 文档转换为可编程的对象结构
- 提供标准化的 API 用于操作页面元素
- 实现 JavaScript 与 HTML 之间的动态交互
1.2 DOM 树
DOM 树是由文档中的所有元素、属性、文本等构成的一种树状结构。它是 DOM 的核心表示形式,每个节点代表文档中的一个部分。以下是 DOM 树的主要组成部分:
- 根节点:在 HTML 文档中,
<html>
标签是 DOM 树的根节点,它是整个文档的起始点。 - 元素节点:每个 HTML 标签对应一个元素节点,如
<head>
、<body>
、<div>
等。元素节点可以包含其他元素节点,形成嵌套结构。 - 属性节点:每个标签的属性(如
id
、class
、src
等)作为一个属性节点,它们总是被包含在元素节点中。 - 文本节点:包含在标签之间的文字内容作为文本节点,例如
<p>Hello, World!</p>
中的 “Hello, World!” 就是一个文本节点。
下面是一个简单的 HTML 示例及其对应的 DOM 树结构:
关键节点类型:
- 根节点:整个 DOM 树的顶层节点,HTML 文档中为
<html>
标签 - 元素节点:对应 HTML 标签,如
<div>
,<p>
等 - 属性节点:标签的属性,如
id
,class
等 - 文本节点:标签内的文字内容,如
<p>Hello</p>
中的 "Hello"
1.3、获取元素
1.3.1 常用获取元素的方法
在操作 DOM 之前,我们需要先获取到要操作的元素。以下是几种常用的获取元素的方法:
方法名称 | 描述 | 返回类型 |
---|---|---|
document.getElementById(id) | 根据指定的id属性值获取唯一的元素 | 单个元素(Element) |
document.getElementsByClassName(className) | 根据指定的class名称获取一组元素 | 类数组对象(HTMLCollection) |
document.getElementsByTagName(tagName) | 根据指定的HTML标签名获取一组元素 | 类数组对象(HTMLCollection) |
document.querySelector(selector) | 使用CSS选择器语法匹配第一个符合条件的元素 | 单个元素(Element) |
document.querySelectorAll(selector) | 使用CSS选择器语法匹配所有符合条件的元素 | 类数组对象(NodeList) |
①document.getElementById(id)
- 作用:根据元素的唯一 id 属性获取单个元素
- 返回值:单个元素对象(若不存在则返回 null)
- 推荐场景:已知元素唯一标识时使用
<body><div id="mybox">我爱学javascript!</div><div id="mybox1">我爱学Python!</div><script>let mybox_elment = document.getElementById('mybox');console.log(mybox_elment,typeof mybox_elment)</script>
</body>
②document.getElementsByClassName(className)
- 作用:根据类名获取一组元素
- 返回值:类数组对象(HTMLCollection)
- 注意:返回的是动态集合,会随文档变化自动更新
<body>
<p class="myClass">我是一个p标签</p>
<p class="myClass">我是一个p标签</p>
<p class="myClass">我是一个p标签</p>
<a href="" class="isa">我是a标签</a>
<script>let myClass_elm = document.getElementsByClassName('myClass')console.log(myClass_elm)for(let i = 0;i<myClass_elm.length;i++){console.log(myClass_elm[i])}
</script>
</body>
③document.getElementsByTagName(tagName)
- 作用:根据标签名获取一组元素
- 返回值:类数组对象(HTMLCollection)
- 示例:获取页面中所有
<a>
标签
<body>
<ul class="nav" id = "nav1"><li>我是帅哥列表!</li><li>我是帅哥列表!</li><li>我是帅哥列表!</li>
</ul>
<ul class="nav" id = "nav2"><li>我是美女列表!</li><li>我是美女列表!</li><li>我是美女列表!</li>
</ul>
<script>let nav_elm = document.getElementsByTagName('ul')console.log(nav_elm)let li_elm = nav_elm[0].getElementsByTagName('li')console.log(li_elm)for(let i = 0;i<li_elm.length;i++){console.log(li_elm[i])}
</script>
</body>
④ document.querySelector(selector)
- 作用:使用 CSS 选择器匹配第一个符合条件的元素
- 返回值:单个元素对象(若不存在则返回 null)
- 推荐场景:需要灵活选择器时使用
<body>
<ul class="nav" id = "nav1"><li>我是帅哥列表!</li><li>我是帅哥列表!</li><li>我是帅哥列表!</li>
</ul>
<ul class="nav" id = "nav2"><li>我是美女列表!</li><li>我是美女列表!</li><li>我是美女列表!</li>
</ul>
<script>let first_nva = document.querySelector('.nav')console.log(first_nva)let first_li = document.querySelector('.nav li')console.log(first_li)
</script>
</body>
⑤document.querySelectorAll(selector)
- 作用:使用 CSS 选择器匹配所有符合条件的元素
- 返回值:类数组对象(NodeList)
- 优势:支持所有 CSS 选择器,且返回静态集合
<body>
<ul class="nav" id = "nav1"><li>我是帅哥列表!</li><li>我是帅哥列表!</li><li>我是帅哥列表!</li>
</ul>
<ul class="nav" id = "nav2"><li>我是美女列表!</li><li>我是美女列表!</li><li>我是美女列表!</li>
</ul>
<script>let li_all = document.querySelectorAll('.nav li')for (let i = 0;i<li_all.length;i++){console.log(li_all[i])}
</script>
</body>
1.3.2 获取元素的注意事项
-
类数组与数组的区别:
- 类数组(如 HTMLCollection、NodeList)拥有索引和 length 属性,但没有数组方法(如
push()
,forEach()
) - 转换方法:
Array.from(collection)
或[...collection]
- 类数组(如 HTMLCollection、NodeList)拥有索引和 length 属性,但没有数组方法(如
-
性能优化要点:
- 频繁获取元素时可缓存结果,避免重复查询
querySelectorAll()
返回静态集合,比getElementsByClassName()
更适合需要稳定数据的场景- 复杂选择器(如多层嵌套)可能影响性能,尽量简化选择器
1.3.3 总结:DOM 元素获取的最佳实践
- 优先使用
document.getElementById()
和document.querySelector()
/querySelectorAll()
,因其兼容性和灵活性更优 - 了解不同方法的返回值类型(单个元素 vs 类数组),避免类型错误
- 合理利用选择器语法(如
#id
,.class
,element
,[attribute]
等),提高选择效率
二、事件机制
2.1 事件概述
事件是用户或浏览器执行某种操作时触发的行为,例如点击按钮、滚动页面、键盘输入等。JavaScript 通过事件驱动模型实现与用户的交互 —— 当事件发生时,预先绑定的事件处理程序会被自动执行。
常见事件场景:
- 用户操作:点击、滚动、输入
- 页面状态:加载完成、尺寸变化、错误发生
- 设备交互:触摸、手势、方向变化
2.2 事件三要素
要成功绑定并执行一个事件,必须具备以下三个要素:
- 事件源:触发事件的对象(如按钮、输入框、页面等)
- 事件类型:触发的事件种类(如
click
,keydown
,load
) - 事件处理程序:事件发生时执行的代码逻辑(通常是一个函数)
2.3 绑定事件的两种方式
方式一:直接赋值(on 事件)
<body>
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<button id="btn3">按钮3</button>
<script>
// ①获取事件源(DOM 元素)
let btn1 = document.getElementById('btn1');
let btn2 = document.getElementById('btn2');
let btn3 = document.getElementById('btn3')
// ②注册事件监听器(绑定事件)
// ③编写事件处理函数
btn1.onclick = function () {alert('单击了按钮1');
};
btn2.ondblclick = function () {alert('双击击了按钮2');
}
btn3.onmouseover = function () {alert('鼠标移到了按钮3上');
}
</script>
</body>
方式二:addEventListener () 方法(推荐)
<body>
<button id="btn2">点击我</button>
<script>
// JavaScript 代码
const btn2 = document.getElementById("btn2");
btn2.addEventListener("click", function() {alert("通过 addEventListener 绑定事件");
});// 添加多个事件处理程序
btn2.addEventListener("click", function() {console.log("第二个事件处理程序");
});// 移除事件(需使用命名函数)
const handleClick = function() {console.log("可移除的事件处理程序");
};
btn2.addEventListener("click", handleClick);
btn2.removeEventListener("click", handleClick); // 移除事件
</script>
</body>
两种方式的对比:
特性 | onclick 方式 | addEventListener 方式 |
---|---|---|
绑定多个事件 | 不支持(后绑定会覆盖前一个) | 支持(可添加多个处理程序) |
事件捕获 / 冒泡阶段 | 无法指定 | 可通过第三个参数指定 |
兼容性 | 所有浏览器 | IE9+(IE8 及以下使用 attachEvent) |
2.4 常见鼠标事件(重点)
事件名 | 描述 | 典型应用场景 |
---|---|---|
click | 鼠标单击元素时触发 | 按钮点击、链接跳转 |
dblclick | 鼠标双击元素时触发 | 图片放大、文本选中 |
mousedown | 鼠标按键按下时触发 | 拖拽开始、绘制交互 |
mouseup | 鼠标按键释放时触发 | 拖拽结束、操作完成 |
mousemove | 鼠标在元素上移动时触发 | 鼠标跟随效果、地图导航 |
mouseover | 鼠标移入元素(包括子元素)时触发 | 菜单悬停显示、元素高亮 |
mouseout | 鼠标移出元素(包括子元素)时触发 | 菜单隐藏、高亮消失 |
示例:鼠标事件综合应用
<body>
<div id="mouseAction" style="width: 200px; height: 200px; background-color: #ffffff;">鼠标移动过来呀
</div>
<script>let mouseAction = document.getElementById('mouseAction');let count = 0// 鼠标进入mouseAction.onmousemove = function () {this.style.backgroundColor = 'skyblue'this.textContent='鼠标已进入!'}// 鼠标离开mouseAction.onmouseout = function () {this.style.backgroundColor = 'white'this.textContent='鼠标已离开!'}// 鼠标点击mouseAction.addEventListener('click', function() {count++;this.textContent = `点击次数:${count}`;
});
</script>
</body>
2.5 常见键盘事件(重点)
事件名 | 描述 | 典型应用场景 |
---|---|---|
keydown | 键盘按键按下时触发(包括功能键) | 输入验证、快捷键操作 |
keypress | 键盘字符键按下时触发(不包括功能键) | 文本输入监听、输入法支持 |
keyup | 键盘按键释放时触发 | 输入完成确认、快捷键释放处理 |
示例:键盘事件获取按键信息
<body>
<input type="text" id="shuru" placeholder="请输入:">
<p id = "keyboard">按下键盘查看按键信息</p>
<script>let input = document.getElementById('shuru');let keyboard = document.querySelector('#keyboard')input.addEventListener('keydown',function (e){keyboard.textContent = `按键码:${e.keyCode},键名:${e.key}`// 阻止默认行为(比如按下enter键提交)if(e.keyCode ===13){e.preventDefault()alert('已阻止Enter提交的默认行为')}})
</script>
</body>
三、操作元素
3.1 改变元素内容
1. textContent
:纯文本内容操作
- 作用:获取或设置元素的纯文本内容
- 特点:不解析 HTML 标签,只输出文本内容
<body>
<div id = "box1">这是 <strong>文本</strong> 内容</div><script>// 获取内容let divText = document.getElementById('box1').textContent;console.log(divText); // 输出:这是 文本 内容// 设置内容document.getElementById('box1').textContent = '这是新的纯文本内容';let newdivText = document.getElementById('box1').textContent;console.log(newdivText);</script>
</body>
2. innerText
:可见文本内容操作
- 作用:获取或设置元素的可见文本内容
- 特点:受 CSS 样式影响(如
display: none
的文本不会被获取)
<body>
<div id="innerTextDiv" style="font-size: 20px;">可见文本 <span style="display: none;">隐藏文本</span>
</div>
<script>
const innerText = document.getElementById("innerTextDiv").innerText;
console.log(innerText); // 输出:可见文本 (隐藏文本被忽略)
</script>
</body>
3. innerHTML
:HTML 内容操作
- 作用:获取或设置元素包含的 HTML 内容
- 特点:解析 HTML 标签,可动态插入结构
<body>
<div id="htmlDiv">初始内容</div>
<div id="htmlDiv2">这是 <strong>文本</strong> 内容</div>
<script>// 获取内容const htmlDiv2 = document.getElementById("htmlDiv2");console.log(htmlDiv2.innerHTML); // 这是 <strong>文本</strong> 内容// 设置内容document.getElementById("htmlDiv").innerHTML = `<h3>动态标题</h3><ul><li>列表项1</li><li>列表项2</li></ul>`;
</script>
</body>
3.2 元素属性操作
①获取/设置/移除元素的标准属性:
element.getAttribute('属性名')
element.setAttribute('属性名', '属性值')
element.removeAttribute('属性名')
<body>
<a href="https://baidu.com" id="link" title="链接描述" class="nav-link">百度一下</a>
<script>// 获取属性let a_element = document.getElementById("link");const href = a_element.getAttribute("href")const title = a_element.getAttribute("title")const class_name = a_element.getAttribute("class")console.log(`地址是:${href},链接是:${title},类名是:${class_name}`);// 设置属性a_element.setAttribute("title","百度一下") // 修改title属性为:百度一下console.log(a_element.getAttribute("title")); // 输出:百度一下// 移出属性console.log(a_element.getAttribute('class')); //输出:nav-linka_element.removeAttribute("class")console.log(a_element.getAttribute("class")); //输出:null
</script>
</body>
②直接访问常用属性: src, href, id, className, style 等
<body>
<a href="https://baidu.com" id="link" title="链接描述" class="nav-link">百度一下</a>
<script>let a_element = document.querySelector("#link");console.log(`网址是:${a_element.href},\nid是:${a_element.id}, title是:${a_element.title},类名是:${a_element.class}`);
</script>
</body>
<body>
<img src="../images/ldh.png" id="myimg" class="firstimg" alt="图片">
<script>let img = document.getElementById("myimg");// 直接访问属性console.log(`图片的地址:${img.src},id是:${img.id}`)console.log(`图片的类名:${img.class},描述是:${img.alt}`)// 修改属性// img.src = "../images/zxy.png"img.alt = "新图片"
</script>
</body>
③综合案例:实现点按钮切换图片
<body>
<img src="../images/zxy.png" title="我是张学友" id = 'myimg' style="width: 200px">
<button id = 'zxy'>张学友</button>
<button id = 'ldh'>刘德华</button>
<script>let zxybtn = document.getElementById('zxy');let ldhbtn = document.getElementById('ldh');let img = document.querySelector('#myimg');zxybtn.onclick = function () {img.setAttribute('src','../images/zxy.png')img.setAttribute('title','我是张学友')console.log(`地址是:${img.src} \n图片描述是:${img.title}`)}ldhbtn.onclick = function () {img.setAttribute('src','../images/ldh.png')img.setAttribute('title','我是刘德华')console.log(`地址是:${img.src} \n图片描述是:${img.title}`)}
</script>
</body>
3.3 表单元素属性操作
1. 输入框与单选框:value 属性
<body>
<form action="" method="get"><input type="text" name="username" id="username"><input type="password" name="password" id="password"><input type="submit" value="登录" id = "submitBtn"><input type="radio" name="sex" class="sex" value="男" checked>男<input type="radio" name="sex" class="sex" value="女" >女
</form>
<script>let username = document.getElementById("username");let password = document.getElementById("password");let submitBtn = document.getElementById("submitBtn");let sex = document.getElementsByClassName("sex")[0];submitBtn.addEventListener("click", function (e) {e.preventDefault();console.log(`用户名:${username.value}`);console.log(`密码:${password.value}`);if (sex.checked){console.log(`性别:${sex.value}`);}else{console.log(`性别:女`);}});
</script>
</body>
2.复选框和下拉框:checked属性
<body>
<form action="" method="get"><input type="checkbox" name="hobby" class="hobby" value="看电影" checked>看电影<input type="checkbox" name="hobby" class="hobby" value="看小说">看小说<input type="checkbox" name="hobby" class="hobby" value="看游戏">看游戏<select name="city" id="city"><option value="北京">北京</option><option value="上海">上海</option></select><input type="button" value="提交" id="submitBtn">
</form>
<script>let checkbox = document.getElementsByClassName('hobby');let subbtn = document.getElementById('submitBtn');let select = document.getElementById('city');subbtn.onclick = function (e) {// 获取复选框选中项let selectedHobbies = [];for (let i = 0; i < checkbox.length; i++) {if (checkbox[i].checked) {selectedHobbies.push(checkbox[i].value);}}// 获取下拉框选中项let selectedCity = select.value;// 输出到控制台console.log('选中的爱好:', selectedHobbies);console.log('选择的城市:', selectedCity);}
</script>
</body>
3. 禁用与只读状态
<body>
<input type="text" id="disabledInput" disabled>
<input type="text" id="readonlyInput" readonly value="只读内容">
<script>// 动态设置禁用状态const disabledInput = document.getElementById("disabledInput");disabledInput.disabled = false; // 启用输入框// 动态设置只读状态const readonlyInput = document.getElementById("readonlyInput");readonlyInput.readOnly = false; // 取消只读
</script>
</body>
3.4 样式属性操作
1. 行内样式操作:element.style
<body>
<div id="box" style="height: 100px;width: 100px;background-color: #0be4d5">样式操作实例
</div>
<button id="btn">修改样式</button>
<script>const box = document.getElementById("box");const btn = document.getElementById("btn");btn.onclick = function () {// 修改样式box.style.width = "200px";box.style.height = "200px";box.style.backgroundColor = "#d1bfc5";// 设置新样式box.style.fontFamily = "宋体";box.style.fontSize = "20px";box.style.color = "#5440ff";box.style.border = "5px solid #5440ff";// 获取样式console.log(box.style.width);}
</script>
</body>
2. 类名操作:className 与 classList(推荐)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>操作元素</title>
</head><style>.base-style {width: 200px;height: 200px;border: 1px solid #040303;}.active1{width: 100px;height: 100px;background-color: #28cccf;font-family: "汉仪中黑 197";color: #f30a58;}.active2{width: 300px;height: 300px;background-color: #ff7e8b;font-size: 30px;color: #5440ff;}
</style><body><div id="classDiv" class="base-style">类样式操作</div>
<button id = "classBtn1">覆盖原样式,使用active1</button>
<br>
<button id = "classBtn2">添加样式,使用active2(遵循css的继承和覆盖)</button>
<br>
<button id = "classBtn3">删除样式</button>
<br>
<button id = "classBtn4">实现active1和active2的切换</button><script>let classDiv = document.getElementById('classDiv');let button1 = document.getElementById('classBtn1');let button2 = document.getElementById('classBtn2');let button3 = document.getElementById('classBtn3');let button4 = document.getElementById('classBtn4');button1.onclick = function () {// 方式一:使用 className(会覆盖原有类名)classDiv.className = 'active1';}button2.addEventListener('click', function () {// 方式二:使用 classList(不会覆盖原有类名)classDiv.classList.add('active2');})button3.addEventListener('click', function () {// 方式二:使用 classList(不会覆盖原有类名)classDiv.classList.remove('active2'); // 删除类名classDiv.classList.remove('active1'); // 删除类名})button4.addEventListener('click', function () {// 方式二:使用 classList(不会覆盖原有类名)classDiv.classList.add('active1');classDiv.classList.toggle('active2') //切换类名})
</script></body>
</html>
3.总结:
样式操作方式对比:
操作方式 | 核心语法 | 优点 |
---|---|---|
行内样式(style) | element.style.属性 = 值 | 1. 直接修改,即时生效 2. 可动态计算样式值(如 JS 变量) |
类名操作(className) | element.className = '类名1 类名2' | 1. 样式与逻辑分离,符合 CSS 规范 2. 可批量修改多个样式 |
类名操作(classList) | element.classList.方法(类名) | 1. 提供专用 API,操作更安全 2. 支持添加 / 移除 / 切换 / 检查类名 |
classList
常用方法详解:
方法名 | 参数 | 返回值 | 功能描述 |
---|---|---|---|
add(className) | 类名字符串 | 无 | 向元素添加指定类名,若已存在则不重复添加 |
remove(className) | 类名字符串 | 无 | 从元素移除指定类名,若不存在则无操作 |
toggle(className) | 类名字符串 | 布尔值 | 切换类名:存在则移除,不存在则添加,返回操作后的状态(是否存在) |
总结:DOM 与事件开发的核心要点
1. DOM 操作的核心思维
- 树状结构思维:将 HTML 文档视为由节点组成的树,通过父子、兄弟关系导航元素
- 选择器优先级:优先使用
querySelector
/querySelectorAll
,灵活处理复杂选择场景 - 性能意识:减少频繁 DOM 操作,批量修改元素样式(如使用类名而非逐个样式修改),避免大规模重排重绘
2. 事件开发的最佳实践
- 事件委托:将事件绑定在父元素上,通过
event.target
处理子元素事件,减少事件绑定数量 - 事件对象:熟练使用
event
对象获取事件信息(如鼠标位置、键盘按键、事件源等) - 兼容性处理:了解不同浏览器的事件机制差异(如 IE 中的
attachEvent
),使用库或封装函数统一处理
3. 元素操作的黄金法则
- 内容操作:根据需求选择
textContent
(纯文本)或innerHTML
(HTML 结构) - 属性操作:标准属性使用
getAttribute/setAttribute
,常用属性直接访问 - 样式操作:优先使用类名操作(
classList
),分离样式与逻辑,便于维护
通过掌握 DOM 操作、事件机制和元素操作这三大核心技能,你将能够开发出交互流畅、体验出色的网页应用。在实际开发中,建议结合框架(如 React、Vue)进一步提升开发效率,但底层的 DOM 与事件知识始终是前端开发的根基。