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

JavaScript动态操作DOM元素的实现

2021-12-063.0k 阅读

理解 DOM(文档对象模型)

在深入探讨 JavaScript 如何动态操作 DOM 元素之前,我们需要先对 DOM 有一个清晰的认识。DOM 是一种针对 HTML 和 XML 文档的编程接口,它将文档呈现为一个由节点和对象(包含属性和方法)组成的逻辑树。通过 DOM,JavaScript 可以访问和操作网页的各个部分,实现动态的页面效果。

DOM 树结构

DOM 树的根节点是 document 对象,它代表整个 HTML 文档。从根节点开始,每个 HTML 标签在 DOM 树中都对应一个节点。例如,以下是一个简单的 HTML 结构及其对应的 DOM 树示意:

<!DOCTYPE html>
<html>
<head>
    <title>DOM 示例</title>
</head>
<body>
    <h1>欢迎来到我的页面</h1>
    <p>这是一段示例文本。</p>
</body>
</html>

在 DOM 树中,html 元素是 document 对象的直接子节点,headbodyhtml 元素的子节点,titlehead 元素的子节点,h1pbody 元素的子节点。每个节点都有特定的属性和方法,用于获取和修改其自身的信息以及与其他节点的关系。

节点类型

DOM 中有多种节点类型,常见的包括:

  1. 元素节点(Element Node):代表 HTML 标签,如 divpa 等。元素节点具有属性和子节点,可以包含文本节点和其他元素节点。
  2. 文本节点(Text Node):包含纯文本内容,例如 p 标签内的文本 “这是一段示例文本。” 就是一个文本节点。文本节点没有子节点。
  3. 属性节点(Attribute Node):用于定义元素的属性,如 <a href="https://example.com">链接</a> 中的 href 属性就是一个属性节点。

了解这些节点类型对于 JavaScript 操作 DOM 元素至关重要,因为不同的操作可能适用于不同类型的节点。

获取 DOM 元素

在 JavaScript 中,获取 DOM 元素是动态操作的第一步。有多种方法可以获取特定的 DOM 元素,下面我们详细介绍这些方法及其应用场景。

通过 ID 获取元素

每个 HTML 元素都可以设置一个唯一的 id 属性。JavaScript 提供了 document.getElementById() 方法来通过 id 获取对应的元素。例如:

<!DOCTYPE html>
<html>
<body>
    <div id="myDiv">这是一个 div 元素</div>
    <script>
        var myDiv = document.getElementById('myDiv');
        console.log(myDiv);
    </script>
</body>
</html>

在上述代码中,document.getElementById('myDiv') 返回 idmyDivdiv 元素,并将其赋值给变量 myDiv。然后通过 console.log() 打印该元素对象。这种方法简单直接,适用于获取页面中唯一标识的元素。

通过标签名获取元素

如果要获取页面中所有具有相同标签名的元素,可以使用 document.getElementsByTagName() 方法。该方法返回一个 HTMLCollection 对象,它是一个类似数组的集合,包含了所有匹配标签名的元素。例如:

<!DOCTYPE html>
<html>
<body>
    <p>段落 1</p>
    <p>段落 2</p>
    <script>
        var paragraphs = document.getElementsByTagName('p');
        for (var i = 0; i < paragraphs.length; i++) {
            console.log(paragraphs[i].textContent);
        }
    </script>
</body>
</html>

在这段代码中,document.getElementsByTagName('p') 获取了页面中所有的 p 元素,并通过循环打印出每个 p 元素的文本内容。需要注意的是,HTMLCollection 是一个实时集合,这意味着如果文档结构发生变化,该集合会自动更新。

通过类名获取元素

使用 document.getElementsByClassName() 方法可以获取具有指定类名的所有元素。该方法返回一个 HTMLCollection 对象,与 getElementsByTagName() 类似。例如:

<!DOCTYPE html>
<html>
<body>
    <div class="myClass">Div 1</div>
    <div class="myClass">Div 2</div>
    <script>
        var divs = document.getElementsByClassName('myClass');
        for (var i = 0; i < divs.length; i++) {
            divs[i].style.backgroundColor = 'lightblue';
        }
    </script>
</body>
</html>

在此代码中,document.getElementsByClassName('myClass') 获取了所有类名为 myClassdiv 元素,并通过循环为每个 div 元素设置背景颜色。

使用 querySelector 和 querySelectorAll

document.querySelector() 方法返回文档中匹配指定 CSS 选择器的第一个元素。document.querySelectorAll() 方法则返回所有匹配指定 CSS 选择器的元素的 NodeList 对象。这两个方法提供了一种更灵活的方式来获取元素,因为可以使用各种 CSS 选择器。例如:

<!DOCTYPE html>
<html>
<body>
    <ul>
        <li class="item">列表项 1</li>
        <li class="item selected">列表项 2</li>
        <li class="item">列表项 3</li>
    </ul>
    <script>
        // 获取第一个类名为 item 的元素
        var firstItem = document.querySelector('.item');
        console.log(firstItem);

        // 获取所有类名为 item 且具有 selected 类的元素
        var selectedItems = document.querySelectorAll('.item.selected');
        for (var i = 0; i < selectedItems.length; i++) {
            console.log(selectedItems[i].textContent);
        }
    </script>
</body>
</html>

在上述代码中,querySelector('.item') 获取了第一个类名为 itemli 元素,而 querySelectorAll('.item.selected') 获取了所有同时具有 itemselected 类的 li 元素。NodeList 与 HTMLCollection 类似,但它不是实时集合,文档结构变化不会自动更新 NodeList。

操作 DOM 元素的属性

获取到 DOM 元素后,我们可以对其属性进行操作,包括读取、修改和添加属性。

读取属性

可以通过元素对象的属性名直接读取一些常见的属性,例如 src 属性用于 img 元素,href 属性用于 a 元素等。对于其他属性,可以使用 getAttribute() 方法。例如:

<!DOCTYPE html>
<html>
<body>
    <img id="myImage" src="image.jpg" alt="示例图片">
    <script>
        var myImage = document.getElementById('myImage');
        // 直接读取 src 属性
        console.log(myImage.src);
        // 使用 getAttribute 读取 alt 属性
        console.log(myImage.getAttribute('alt'));
    </script>
</body>
</html>

在这段代码中,myImage.src 直接获取 img 元素的 src 属性值,myImage.getAttribute('alt') 使用 getAttribute() 方法获取 alt 属性值。

修改属性

修改属性同样可以通过直接赋值或 setAttribute() 方法。例如,要修改 img 元素的 src 属性:

<!DOCTYPE html>
<html>
<body>
    <img id="myImage" src="image1.jpg" alt="图片 1">
    <button onclick="changeImage()">更换图片</button>
    <script>
        function changeImage() {
            var myImage = document.getElementById('myImage');
            // 直接赋值修改 src 属性
            myImage.src = 'image2.jpg';
            // 使用 setAttribute 修改 alt 属性
            myImage.setAttribute('alt', '图片 2');
        }
    </script>
</body>
</html>

当点击按钮时,changeImage() 函数被调用,通过直接赋值修改 src 属性,通过 setAttribute() 方法修改 alt 属性。

添加属性

可以使用 setAttribute() 方法为元素添加新的属性。例如,为一个 div 元素添加 data - custom 属性:

<!DOCTYPE html>
<html>
<body>
    <div id="myDiv">这是一个 div</div>
    <script>
        var myDiv = document.getElementById('myDiv');
        myDiv.setAttribute('data - custom', '自定义数据');
        console.log(myDiv.getAttribute('data - custom'));
    </script>
</body>
</html>

在上述代码中,setAttribute('data - custom', '自定义数据')div 元素添加了 data - custom 属性,并通过 getAttribute() 方法验证其添加成功。

操作 DOM 元素的样式

JavaScript 可以动态修改 DOM 元素的样式,从而实现丰富的视觉效果。

通过 style 属性直接修改

每个 DOM 元素都有一个 style 属性,通过该属性可以直接设置元素的内联样式。例如,修改 div 元素的背景颜色和字体大小:

<!DOCTYPE html>
<html>
<body>
    <div id="myDiv">这是一个 div</div>
    <script>
        var myDiv = document.getElementById('myDiv');
        myDiv.style.backgroundColor = 'yellow';
        myDiv.style.fontSize = '20px';
    </script>
</body>
</html>

在这段代码中,myDiv.style.backgroundColormyDiv.style.fontSize 分别设置了 div 元素的背景颜色和字体大小。需要注意的是,CSS 属性名中如果有连字符(如 font - size),在 JavaScript 中需要使用驼峰命名法(fontSize)。

使用类名切换样式

另一种常见的方式是通过添加或移除类名来切换样式。可以使用 classList 属性,它提供了方便的方法来操作元素的类名。例如,假设有以下 CSS 样式:

.normal {
    background - color: white;
    color: black;
}
.highlight {
    background - color: yellow;
    color: red;
}

在 HTML 中使用 JavaScript 切换类名:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
    <div id="myDiv" class="normal">这是一个 div</div>
    <button onclick="toggleClass()">切换样式</button>
    <script>
        function toggleClass() {
            var myDiv = document.getElementById('myDiv');
            if (myDiv.classList.contains('normal')) {
                myDiv.classList.remove('normal');
                myDiv.classList.add('highlight');
            } else {
                myDiv.classList.remove('highlight');
                myDiv.classList.add('normal');
            }
        }
    </script>
</body>
</html>

当点击按钮时,toggleClass() 函数检查 div 元素当前的类名,并根据情况添加或移除相应的类名,从而切换样式。

创建和插入新的 DOM 元素

除了操作已有的 DOM 元素,JavaScript 还可以创建新的元素并将其插入到文档中。

创建元素

使用 document.createElement() 方法可以创建一个新的元素节点。例如,创建一个新的 p 元素:

<!DOCTYPE html>
<html>
<body>
    <script>
        var newParagraph = document.createElement('p');
        newParagraph.textContent = '这是一个新创建的段落。';
        console.log(newParagraph);
    </script>
</body>
</html>

在上述代码中,document.createElement('p') 创建了一个新的 p 元素,然后通过 textContent 属性为其设置文本内容。

插入元素

创建好元素后,可以使用以下方法将其插入到文档中:

appendChild()

appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。例如,将刚才创建的 p 元素添加到 body 元素中:

<!DOCTYPE html>
<html>
<body>
    <script>
        var newParagraph = document.createElement('p');
        newParagraph.textContent = '这是一个新创建的段落。';
        document.body.appendChild(newParagraph);
    </script>
</body>
</html>

insertBefore()

insertBefore() 方法在指定的子节点之前插入一个新的子节点。它接受两个参数,第一个参数是要插入的节点,第二个参数是参照节点。例如,在一个已有 p 元素之前插入新的 p 元素:

<!DOCTYPE html>
<html>
<body>
    <p id="existingParagraph">这是已有的段落。</p>
    <script>
        var newParagraph = document.createElement('p');
        newParagraph.textContent = '这是新插入的段落。';
        var existingParagraph = document.getElementById('existingParagraph');
        document.body.insertBefore(newParagraph, existingParagraph);
    </script>
</body>
</html>

在这段代码中,document.body.insertBefore(newParagraph, existingParagraph) 将新创建的 p 元素插入到 idexistingParagraphp 元素之前。

删除 DOM 元素

删除 DOM 元素同样是常见的操作之一。要删除一个元素,需要先获取该元素及其父元素,然后使用父元素的 removeChild() 方法。例如,删除一个 div 元素:

<!DOCTYPE html>
<html>
<body>
    <div id="myDiv">这是要删除的 div</div>
    <button onclick="deleteDiv()">删除 div</button>
    <script>
        function deleteDiv() {
            var myDiv = document.getElementById('myDiv');
            var parent = myDiv.parentNode;
            if (parent) {
                parent.removeChild(myDiv);
            }
        }
    </script>
</body>
</html>

当点击按钮时,deleteDiv() 函数获取 div 元素及其父元素,然后使用 parent.removeChild(myDiv) 删除 div 元素。需要注意的是,在调用 removeChild() 之前,最好先检查父元素是否存在,以避免错误。

事件处理与 DOM 动态操作

事件处理是 JavaScript 动态操作 DOM 的重要组成部分。通过为 DOM 元素添加事件监听器,可以在特定事件发生时执行相应的操作。

常见事件类型

  1. 点击事件(Click Event):当用户点击元素时触发,例如按钮的点击操作。
  2. 鼠标移入移出事件(Mouse Events)mouseenter 事件在鼠标指针进入元素时触发,mouseleave 事件在鼠标指针离开元素时触发。
  3. 键盘事件(Keyboard Events):如 keydownkeyup 等事件,在用户按下或释放键盘按键时触发。
  4. 表单事件(Form Events):例如 submit 事件在表单提交时触发,input 事件在输入框内容改变时触发。

添加事件监听器

可以使用 addEventListener() 方法为 DOM 元素添加事件监听器。该方法接受三个参数:事件类型(如 'click')、事件处理函数、以及一个可选的布尔值(用于指定事件冒泡或捕获阶段)。例如,为按钮添加点击事件监听器:

<!DOCTYPE html>
<html>
<body>
    <button id="myButton">点击我</button>
    <script>
        var myButton = document.getElementById('myButton');
        myButton.addEventListener('click', function() {
            alert('按钮被点击了!');
        });
    </script>
</body>
</html>

在上述代码中,myButton.addEventListener('click', function() { ... }) 为按钮添加了点击事件监听器,当按钮被点击时,会弹出一个提示框。

事件对象

在事件处理函数中,可以通过参数获取事件对象,该对象包含了与事件相关的各种信息。例如,在点击事件中,可以获取鼠标点击的位置:

<!DOCTYPE html>
<html>
<body>
    <div id="myDiv">点击这个 div</div>
    <script>
        var myDiv = document.getElementById('myDiv');
        myDiv.addEventListener('click', function(event) {
            console.log('鼠标点击位置:X ='+ event.clientX + ', Y ='+ event.clientY);
        });
    </script>
</body>
</html>

在这段代码中,event.clientXevent.clientY 分别表示鼠标点击位置相对于浏览器窗口的水平和垂直坐标。

通过深入理解上述内容,开发者可以熟练运用 JavaScript 实现对 DOM 元素的各种动态操作,从而创建出交互性强、动态效果丰富的网页应用。无论是简单的样式切换,还是复杂的页面结构动态生成与修改,都可以通过合理运用这些技术来实现。同时,在实际开发中,要注意性能问题,避免频繁操作 DOM 导致页面性能下降,尽量批量操作或者使用文档片段(DocumentFragment)来减少对 DOM 树的直接操作次数。