【前端教程】JavaScript DOM 操作案例解析与代码优化
·
案例1:获取div子节点并批量修改样式与内容
功能解析
该案例实现两个核心功能:获取div下所有子节点并设置红色背景;识别所有p标签并修改其内容为"我爱中国"。
原代码分析
window.onload=function(){
// 获取div下所有元素节点
var ziJieDianDivShuZu = document.getElementsByTagName("div")[0].children;
// 设置所有子节点背景为红色
for(var i of ziJieDianDivShuZu){
i.style.backgroundColor="red";
}
// 获取div下所有p标签
var jieDianPShuZu=document.getElementsByTagName("div")[0].getElementsByTagName("p");
// 修改p标签内容
for(var i of jieDianPShuZu){
i.innerHTML="我爱中国";
}
}
优化建议
-
缓存DOM查询结果:避免重复查询相同元素
// 优化后 var div = document.querySelector("div"); // 使用更简洁的querySelector var children = div.children; -
合并操作减少遍历:可以在一个循环中完成两种操作
for(var child of children) { child.style.backgroundColor = "red"; if(child.tagName === "P") { // 检查是否为p标签 child.textContent = "我爱中国"; // 纯文本内容推荐使用textContent } } -
使用更现代的API:querySelector和querySelectorAll更灵活
// 直接获取所有p标签 var pTags = div.querySelectorAll("p");
案例2:ul下子节点隔行换色效果
功能解析
实现鼠标悬停在ul的li元素上时,奇数项和偶数项显示不同的背景色,移开时恢复默认黄色。
原代码分析
window.onload=function(){
var ulFirstNeiRong = document.getElementsByTagName("ul")[0];
var jiShuZu = ulFirstNeiRong.getElementsByClassName("jiID");
var ouShuZu = ulFirstNeiRong.getElementsByClassName("ouID");
// 奇数项事件
for(var i of jiShuZu){
i.onmouseover=function(){
this.style.backgroundColor="red";
}
i.onmouseout=function(){
this.style.backgroundColor="yellow";
}
}
// 偶数项事件
for(var i of ouShuZu){
i.onmouseover=function(){
this.style.backgroundColor="green";
}
i.onmouseout=function(){
this.style.backgroundColor="yellow";
}
}
}
优化建议
-
移除冗余类名:不需要提前定义奇偶类,可以通过索引判断
var lis = ulFirstNeiRong.querySelectorAll("li"); lis.forEach((li, index) => { // 绑定事件处理函数 li.addEventListener("mouseover", function() { this.style.backgroundColor = index % 2 === 0 ? "red" : "green"; }); li.addEventListener("mouseout", function() { this.style.backgroundColor = "yellow"; }); }); -
使用addEventListener:更灵活的事件绑定方式,支持事件捕获/冒泡控制
-
CSS优化:可以考虑使用CSS伪类结合JS实现,减少DOM操作
/* 可配合使用的CSS */ li:hover { transition: background-color 0.3s; }
案例3:节点类型统计功能
功能解析
实现鼠标移动到ul上时,在div中显示ul包含的各类节点数量:子节点、元素节点、属性节点和文本节点。
原代码分析
window.onload = function() {
var ulFirstNeiRong = document.getElementsByTagName("ul")[0];
var divAllNeiRong = ulFirstNeiRong.nextElementSibling;
ulFirstNeiRong.onmouseover = function() {
var ziJieDanShuZuZongChangDu = this.childNodes.length;
var yuanSuJieDianShuZuZongChangDu = this.children.length;
var shuXingJieDianShuZuZongChangDu = this.attributes.length;
var wenBenJieDianShuZuZongChangDu = 0;
var allJieDianShuZu = this.childNodes;
for(var i of allJieDianShuZu) {
if(i.nodeType == 3) {
wenBenJieDianShuZuZongChangDu++;
}
}
divAllNeiRong.innerHTML = `子节点${ziJieDanShuZuZongChangDu}个<br>
元素节点${yuanSuJieDianShuZuZongChangDu}个<br>
属性节点${shuXingJieDianShuZuZongChangDu}个<br>
文本节点${wenBenJieDianShuZuZongChangDu}个`;
}
}
优化建议
-
使用模板字符串:使HTML拼接更清晰(原代码已部分实现)
-
封装统计逻辑:将节点统计功能封装为函数,提高复用性
function countNodes(element) { const childNodes = element.childNodes; const textNodes = Array.from(childNodes).filter(node => node.nodeType === 3).length; return { total: childNodes.length, elements: element.children.length, attributes: element.attributes.length, text: textNodes }; } -
处理空白文本节点:HTML中的换行和空格会被解析为文本节点,可以过滤空文本
// 优化文本节点计数,排除纯空白文本 if(i.nodeType === 3 && i.textContent.trim() !== '') { wenBenJieDianShuZuZongChangDu++; }
案例4:图片轮播功能
功能解析
实现图片自动轮播效果,鼠标悬停时停止轮播,移开时继续播放。
原代码分析
window.onload=function(){
window.imgShuZu = ["./img/1.jpg","./img/2.jpg","./img/3.jpg"];
window.indexXiaBiao = 0;
window.img = document.getElementsByTagName("img")[0];
window.start = null;
// 鼠标移入停止轮播
window.img.onmouseover=function(){
clearInterval(window.start);
}
// 鼠标移出继续轮播
window.img.onmouseout=function(){
window.start = setInterval(gaiBianFunction, 666);
}
}
function gaiBianFunction(){
if (window.indexXiaBiao <= 2) {
indexXiaBiao++;
}
if (window.indexXiaBiao > 2) {
indexXiaBiao = 0;
}
window.img.src = window.imgShuZu[window.indexXiaBiao];
}
优化建议
-
减少全局变量:使用闭包或IIFE封装变量,避免污染全局作用域
(function() { const imgShuZu = ["./img/1.jpg","./img/2.jpg","./img/3.jpg"]; let indexXiaBiao = 0; const img = document.querySelector("img"); let start = null; // 内部函数可以访问上述变量 function startSlide() { start = setInterval(gaiBianFunction, 666); } // 其他代码... // 页面加载完成后自动开始轮播 startSlide(); })(); -
优化索引计算:使用取模运算简化循环逻辑
function gaiBianFunction() { indexXiaBiao = (indexXiaBiao + 1) % imgShuZu.length; img.src = imgShuZu[indexXiaBiao]; } -
添加图片预加载:避免轮播时图片加载延迟
// 预加载图片 imgShuZu.forEach(src => { const preloadImg = new Image(); preloadImg.src = src; }); -
防止重复设置定时器:在设置新定时器前先清除旧的
window.img.onmouseout = function() { clearInterval(start); // 先清除 start = setInterval(gaiBianFunction, 666); // 再设置 }
总结与扩展
以上四个案例覆盖了DOM操作的核心知识点:节点获取、样式修改、事件处理和动态内容更新。通过优化,我们可以使代码更简洁、高效且易于维护。
扩展建议:
- 学习使用ES6+特性(箭头函数、解构赋值等)简化代码
- 考虑使用事件委托减少事件绑定数量
- 对于复杂DOM操作,可以学习使用Vue、React等框架提高开发效率
- 始终注意DOM操作的性能问题,减少不必要的重绘和回流
更多推荐
所有评论(0)