案例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="我爱中国";
    }
}

优化建议

  1. 缓存DOM查询结果:避免重复查询相同元素

    // 优化后
    var div = document.querySelector("div"); // 使用更简洁的querySelector
    var children = div.children;
    
  2. 合并操作减少遍历:可以在一个循环中完成两种操作

    for(var child of children) {
        child.style.backgroundColor = "red";
        if(child.tagName === "P") { // 检查是否为p标签
            child.textContent = "我爱中国"; // 纯文本内容推荐使用textContent
        }
    }
    
  3. 使用更现代的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";
        }
    }
}

优化建议

  1. 移除冗余类名:不需要提前定义奇偶类,可以通过索引判断

    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";
        });
    });
    
  2. 使用addEventListener:更灵活的事件绑定方式,支持事件捕获/冒泡控制

  3. 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}`;
    }
}

优化建议

  1. 使用模板字符串:使HTML拼接更清晰(原代码已部分实现)

  2. 封装统计逻辑:将节点统计功能封装为函数,提高复用性

    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
        };
    }
    
  3. 处理空白文本节点: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];
}

优化建议

  1. 减少全局变量:使用闭包或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();
    })();
    
  2. 优化索引计算:使用取模运算简化循环逻辑

    function gaiBianFunction() {
        indexXiaBiao = (indexXiaBiao + 1) % imgShuZu.length;
        img.src = imgShuZu[indexXiaBiao];
    }
    
  3. 添加图片预加载:避免轮播时图片加载延迟

    // 预加载图片
    imgShuZu.forEach(src => {
        const preloadImg = new Image();
        preloadImg.src = src;
    });
    
  4. 防止重复设置定时器:在设置新定时器前先清除旧的

    window.img.onmouseout = function() {
        clearInterval(start); // 先清除
        start = setInterval(gaiBianFunction, 666); // 再设置
    }
    

总结与扩展

以上四个案例覆盖了DOM操作的核心知识点:节点获取、样式修改、事件处理和动态内容更新。通过优化,我们可以使代码更简洁、高效且易于维护。

扩展建议:

  1. 学习使用ES6+特性(箭头函数、解构赋值等)简化代码
  2. 考虑使用事件委托减少事件绑定数量
  3. 对于复杂DOM操作,可以学习使用Vue、React等框架提高开发效率
  4. 始终注意DOM操作的性能问题,减少不必要的重绘和回流

更多推荐