MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

JavaScript批量修改DOM样式的方法

2021-04-285.3k 阅读

JavaScript批量修改DOM样式的方法

理解DOM(文档对象模型)

在深入探讨如何批量修改DOM样式之前,我们首先需要对DOM有一个清晰的认识。DOM是一种用于HTML和XML文档的编程接口。它将文档呈现为一个由节点和对象(包含属性和方法)组成的结构集合,这些节点和对象的类型和层次关系定义了文档的逻辑结构。简单来说,DOM为JavaScript提供了一种访问和操作HTML页面元素的方式。

例如,假设我们有以下简单的HTML结构:

<!DOCTYPE html>
<html>
<head>
    <title>DOM示例</title>
</head>
<body>
    <div id="myDiv">这是一个div元素</div>
    <script>
        // 获取id为myDiv的元素
        const myDiv = document.getElementById('myDiv');
        console.log(myDiv);
    </script>
</body>
</html>

在上述代码中,document.getElementById('myDiv') 这行代码通过DOM接口获取了页面中id为 myDiv 的元素。一旦获取到该元素,我们就可以对其进行各种操作,包括修改样式。

JavaScript操作样式的基本方式

  1. 通过style属性直接操作 在JavaScript中,每个DOM元素都有一个 style 属性,通过这个属性可以直接设置元素的样式。例如,要改变一个元素的颜色和字体大小:
<!DOCTYPE html>
<html>
<head>
    <title>通过style属性操作样式</title>
</head>
<body>
    <p id="myPara">这是一个段落</p>
    <script>
        const para = document.getElementById('myPara');
        para.style.color ='red';
        para.style.fontSize = '20px';
    </script>
</body>
</html>

在这个例子中,我们获取了id为 myPara 的段落元素,并通过 style 属性分别设置了它的颜色为红色,字体大小为20像素。需要注意的是,使用 style 属性设置样式时,CSS属性名需要采用驼峰命名法,例如 font-size 在JavaScript中要写成 fontSize

  1. 通过className属性切换类 另一种常见的方式是通过 className 属性来切换元素的CSS类。首先,我们在CSS文件中定义好不同的样式类:
.red-text {
    color: red;
}
.big-font {
    font-size: 20px;
}

然后在JavaScript中通过修改 className 属性来应用这些类:

<!DOCTYPE html>
<html>
<head>
    <title>通过className操作样式</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <p id="myPara">这是一个段落</p>
    <script>
        const para = document.getElementById('myPara');
        para.className ='red-text big-font';
    </script>
</body>
</html>

在上述代码中,我们将 myPara 元素的 className 设置为 red-text big-font,这样该元素就会应用这两个CSS类所定义的样式。这种方式在管理复杂样式时非常有用,因为我们可以在CSS文件中集中定义样式,而在JavaScript中只需要简单地切换类名。

批量修改DOM样式的需求场景

  1. 页面交互效果 在许多Web应用中,当用户进行某些操作时,需要批量改变一组元素的样式。例如,在一个图片画廊中,当用户点击“放大”按钮时,所有图片都需要同时放大,这就涉及到批量修改图片元素的 widthheight 等样式属性。
  2. 主题切换 许多网站提供主题切换功能,比如从亮色主题切换到暗色主题。这通常意味着需要批量修改页面中大量元素的背景颜色、文本颜色等样式,以适应新的主题风格。
  3. 响应式布局调整 随着屏幕尺寸的变化,为了实现响应式布局,可能需要批量修改一组元素的显示方式。例如,在移动设备上,某些导航菜单可能需要从水平排列改为垂直排列,这就需要修改相关元素的 displayflex-direction 等样式属性。

批量修改DOM样式的方法

  1. 使用循环遍历元素集合 如果我们知道需要修改样式的元素具有相同的特征,比如相同的标签名、类名或者在DOM树中的特定位置,我们可以通过 document.getElementsByTagNamedocument.getElementsByClassNamedocument.querySelectorAll 获取元素集合,然后通过循环遍历集合来逐个修改样式。

通过标签名批量修改样式 假设我们有多个 p 标签元素,要将它们的颜色都改为蓝色:

<!DOCTYPE html>
<html>
<head>
    <title>通过标签名批量修改样式</title>
</head>
<body>
    <p>段落1</p>
    <p>段落2</p>
    <p>段落3</p>
    <script>
        const paras = document.getElementsByTagName('p');
        for (let i = 0; i < paras.length; i++) {
            paras[i].style.color = 'blue';
        }
    </script>
</body>
</html>

在这个例子中,document.getElementsByTagName('p') 获取了页面中所有的 p 标签元素,然后通过 for 循环遍历这个集合,对每个 p 元素设置颜色为蓝色。

通过类名批量修改样式 如果元素具有相同的类名,我们可以使用 document.getElementsByClassName 来获取元素集合并修改样式。例如,我们有一些具有 highlight 类的元素,要为它们添加一个黄色背景:

<!DOCTYPE html>
<html>
<head>
    <title>通过类名批量修改样式</title>
</head>
<body>
    <div class="highlight">div 1</div>
    <span class="highlight">span 1</span>
    <p class="highlight">段落</p>
    <script>
        const elements = document.getElementsByClassName('highlight');
        for (let i = 0; i < elements.length; i++) {
            elements[i].style.backgroundColor = 'yellow';
        }
    </script>
</body>
</html>

这里通过 document.getElementsByClassName('highlight') 获取了所有具有 highlight 类的元素,然后循环遍历为它们设置背景颜色为黄色。

使用querySelectorAll批量修改样式 document.querySelectorAll 方法可以使用CSS选择器来获取元素集合,这使得我们可以更灵活地选择需要修改样式的元素。例如,要修改所有 div 元素内部的 a 标签的文本装饰为无:

<!DOCTYPE html>
<html>
<head>
    <title>使用querySelectorAll批量修改样式</title>
</head>
<body>
    <div>
        <a href="#">链接1</a>
    </div>
    <div>
        <a href="#">链接2</a>
    </div>
    <script>
        const links = document.querySelectorAll('div a');
        for (let i = 0; i < links.length; i++) {
            links[i].style.textDecoration = 'none';
        }
    </script>
</body>
</html>

在上述代码中,document.querySelectorAll('div a') 选择了所有 div 元素内部的 a 标签,然后通过循环为这些链接去除了文本装饰。

  1. 通过操作类名批量应用样式 正如前面提到的通过 className 属性切换类,我们也可以利用这个方法来批量修改样式。首先,在CSS中定义好需要应用的样式类:
.hidden {
    display: none;
}
.visible {
    display: block;
}

假设我们有一组具有 item 类的元素,当用户点击某个按钮时,要将它们全部隐藏或显示。我们可以这样实现:

<!DOCTYPE html>
<html>
<head>
    <title>通过操作类名批量应用样式</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <button id="toggleButton">切换显示</button>
    <div class="item">项目1</div>
    <div class="item">项目2</div>
    <div class="item">项目3</div>
    <script>
        const toggleButton = document.getElementById('toggleButton');
        const items = document.getElementsByClassName('item');
        toggleButton.addEventListener('click', function() {
            for (let i = 0; i < items.length; i++) {
                if (items[i].classList.contains('hidden')) {
                    items[i].classList.remove('hidden');
                    items[i].classList.add('visible');
                } else {
                    items[i].classList.remove('visible');
                    items[i].classList.add('hidden');
                }
            }
        });
    </script>
</body>
</html>

在这段代码中,我们首先获取了按钮和具有 item 类的元素集合。当按钮被点击时,通过循环遍历 item 元素集合,根据元素当前是否包含 hidden 类来决定是添加还是移除 hiddenvisible 类,从而实现批量隐藏或显示这些元素。

  1. 使用CSS变量和JavaScript动态修改 CSS变量(也称为自定义属性)为我们提供了一种在JavaScript中动态控制样式的强大方式。首先,在CSS中定义变量:
:root {
    --main-color: blue;
}
body {
    color: var(--main-color);
}

然后在JavaScript中可以通过 document.documentElement.style 来修改这个变量的值,从而批量影响使用了该变量的所有元素的样式。例如,我们添加一个按钮,点击按钮可以改变 --main-color 的值,进而改变页面文本颜色:

<!DOCTYPE html>
<html>
<head>
    <title>使用CSS变量和JavaScript动态修改样式</title>
    <style>
        :root {
            --main-color: blue;
        }
        body {
            color: var(--main-color);
        }
    </style>
</head>
<body>
    <button id="changeColorButton">改变颜色</button>
    <p>这是一个段落</p>
    <script>
        const changeColorButton = document.getElementById('changeColorButton');
        changeColorButton.addEventListener('click', function() {
            document.documentElement.style.setProperty('--main-color','red');
        });
    </script>
</body>
</html>

在这个例子中,当点击按钮时,document.documentElement.style.setProperty('--main-color','red') 这行代码将 --main-color 的值从蓝色改为红色,由于 body 元素的 color 属性使用了这个变量,所以页面上所有文本的颜色都随之改变。这种方式特别适合实现主题切换等功能,因为可以通过修改少量的CSS变量来批量改变整个页面的样式风格。

  1. 使用JavaScript库(如jQuery)进行批量样式修改 虽然原生JavaScript已经提供了强大的DOM操作能力,但一些JavaScript库如jQuery可以进一步简化操作。首先,需要引入jQuery库:
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

假设我们有一组 li 元素,要为它们添加一个绿色背景:

<!DOCTYPE html>
<html>
<head>
    <title>使用jQuery批量修改样式</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <ul>
        <li>列表项1</li>
        <li>列表项2</li>
        <li>列表项3</li>
    </ul>
    <script>
        $(document).ready(function() {
            $('li').css('background-color', 'green');
        });
    </script>
</body>
</html>

在上述代码中,$(document).ready 确保在文档完全加载后执行代码。$('li') 选择了所有的 li 元素,然后通过 css 方法批量为它们设置了背景颜色为绿色。jQuery的语法相对简洁,对于不熟悉原生JavaScript复杂DOM操作的开发者来说更容易上手。然而,随着现代JavaScript的发展,原生JavaScript的功能越来越强大,使用库的必要性在某些场景下有所降低,而且引入库会增加页面的加载体积。

性能优化考虑

  1. 减少重排和重绘 当我们修改DOM元素的样式时,浏览器可能需要重新计算元素的布局(重排)和重新绘制元素(重绘)。频繁的重排和重绘会导致性能下降。为了减少这种情况,可以尽量批量修改样式,而不是逐个修改。例如,不要在循环中每次都修改元素的不同样式属性,而是先将要修改的样式属性收集起来,最后一次性应用到元素上。
<!DOCTYPE html>
<html>
<head>
    <title>性能优化 - 减少重排重绘</title>
</head>
<body>
    <div id="myDiv">这是一个div元素</div>
    <script>
        const myDiv = document.getElementById('myDiv');
        const newStyles = {
            color: 'blue',
            fontSize: '20px',
            backgroundColor: 'yellow'
        };
        const styleString = '';
        for (let prop in newStyles) {
            styleString += `${prop}:${newStyles[prop]};`;
        }
        myDiv.style.cssText = styleString;
    </script>
</body>
</html>

在这个例子中,我们先定义了一个包含所有要修改样式属性的对象 newStyles,然后通过循环将这些属性拼接成一个CSS文本字符串,最后通过 cssText 属性一次性应用到元素上,这样只触发一次重排和重绘。

  1. 避免频繁查询DOM 每次查询DOM(例如使用 getElementByIdquerySelectorAll 等方法)都会消耗一定的性能。如果在循环中多次查询DOM,会严重影响性能。尽量在循环外部获取需要操作的元素集合,并保存起来供循环使用。
<!DOCTYPE html>
<html>
<head>
    <title>性能优化 - 避免频繁查询DOM</title>
</head>
<body>
    <div class="box">盒子1</div>
    <div class="box">盒子2</div>
    <div class="box">盒子3</div>
    <script>
        const boxes = document.getElementsByClassName('box');
        for (let i = 0; i < boxes.length; i++) {
            boxes[i].style.color = 'green';
        }
    </script>
</body>
</html>

在上述代码中,我们在循环外部获取了所有具有 box 类的元素集合 boxes,然后在循环中直接使用这个集合,避免了在每次循环中重复查询DOM。

  1. 使用 requestAnimationFrame 进行动画相关的样式修改 如果批量修改样式涉及到动画效果,使用 requestAnimationFrame 可以优化性能。requestAnimationFrame 会在浏览器下一次重绘之前调用指定的回调函数,这样可以确保动画在合适的时机进行样式更新,避免不必要的重绘和性能浪费。
<!DOCTYPE html>
<html>
<head>
    <title>使用requestAnimationFrame优化动画样式修改</title>
</head>
<body>
    <div id="animateDiv">动画div</div>
    <script>
        const div = document.getElementById('animateDiv');
        let offset = 0;
        function animate() {
            offset += 5;
            div.style.transform = `translateX(${offset}px)`;
            if (offset < 200) {
                requestAnimationFrame(animate);
            }
        }
        requestAnimationFrame(animate);
    </script>
</body>
</html>

在这个动画示例中,requestAnimationFrame 会按照浏览器的刷新率来调用 animate 函数,每次更新 div 元素的 transform 样式,实现平滑的动画效果,同时优化了性能。

兼容性考虑

  1. 不同浏览器对CSS属性的支持差异 虽然现代浏览器对CSS属性的支持越来越统一,但仍然存在一些差异。例如,一些较新的CSS属性(如 backdrop-filter)在某些旧版本浏览器中可能不支持。在批量修改样式时,需要考虑到这种兼容性问题。可以通过使用CSS前缀来解决部分兼容性问题,例如:
.element {
    -webkit-backdrop-filter: blur(5px); /* Safari 和 Chrome */
    backdrop-filter: blur(5px); /* 标准语法 */
}

在JavaScript中,如果需要动态设置这些属性,也需要相应地处理前缀。例如:

<!DOCTYPE html>
<html>
<head>
    <title>兼容性 - CSS属性前缀</title>
</head>
<body>
    <div id="myDiv">这是一个div元素</div>
    <script>
        const myDiv = document.getElementById('myDiv');
        function setBackdropFilter() {
            if ('backdropFilter' in document.documentElement.style) {
                myDiv.style.backdropFilter = 'blur(5px)';
            } else if ('WebkitBackdropFilter' in document.documentElement.style) {
                myDiv.style.WebkitBackdropFilter = 'blur(5px)';
            }
        }
        setBackdropFilter();
    </script>
</body>
</html>

在上述代码中,我们首先检查浏览器是否支持标准的 backdropFilter 属性,如果不支持,则检查是否支持WebKit内核浏览器的前缀版本 WebkitBackdropFilter

  1. JavaScript方法的兼容性 一些较新的JavaScript方法(如 querySelectorAll)在旧版本浏览器中可能不存在。可以通过编写兼容性代码或者使用JavaScript库(如jQuery,它已经处理了很多兼容性问题)来解决。例如,对于 querySelectorAll 的兼容性实现:
<!DOCTYPE html>
<html>
<head>
    <title>兼容性 - JavaScript方法</title>
</head>
<body>
    <div class="target">目标div 1</div>
    <div class="target">目标div 2</div>
    <script>
        if (!document.querySelectorAll) {
            document.querySelectorAll = function(selector) {
                const elements = [];
                const allElements = document.getElementsByTagName('*');
                for (let i = 0; i < allElements.length; i++) {
                    if (allElements[i].matches(selector)) {
                        elements.push(allElements[i]);
                    }
                }
                return elements;
            };
        }
        const targets = document.querySelectorAll('.target');
        for (let i = 0; i < targets.length; i++) {
            targets[i].style.color ='red';
        }
    </script>
</body>
</html>

在这段代码中,我们首先检查 document.querySelectorAll 是否存在,如果不存在,则自行实现一个简单的 querySelectorAll 功能,然后再使用它来选择元素并修改样式。

  1. 事件处理兼容性 不同浏览器对事件处理的实现也可能存在差异。例如,在添加事件监听器时,IE浏览器使用 attachEvent 方法,而其他现代浏览器使用 addEventListener 方法。为了实现兼容性,可以编写一个兼容的事件绑定函数:
<!DOCTYPE html>
<html>
<head>
    <title>兼容性 - 事件处理</title>
</head>
<body>
    <button id="myButton">点击我</button>
    <script>
        function addEvent(element, eventType, handler) {
            if (element.addEventListener) {
                element.addEventListener(eventType, handler, false);
            } else if (element.attachEvent) {
                element.attachEvent('on' + eventType, handler);
            }
        }
        const myButton = document.getElementById('myButton');
        addEvent(myButton, 'click', function() {
            alert('按钮被点击了');
        });
    </script>
</body>
</html>

在这个例子中,addEvent 函数会根据浏览器的类型选择合适的方法来添加事件监听器,确保在不同浏览器中都能正常绑定事件。

通过深入理解DOM、掌握各种批量修改DOM样式的方法、注意性能优化和兼容性问题,我们能够在JavaScript开发中更高效、更稳定地实现页面样式的动态修改,为用户带来更好的体验。无论是简单的页面交互还是复杂的Web应用开发,这些知识都将是非常宝贵的。在实际项目中,需要根据具体需求和目标浏览器的情况,灵活选择合适的方法来批量修改DOM样式。