前端学习10:JavaScript-DOM操作之节点操作(增删改查)小白入门+案例实操

前言:适合有基础的同学入门尝试 / 复习回忆。


本章先学习DOM操作的节点操作 ,事件处理下节再学。

什么是DOM操作?——DOM(Document Object Model)是文档对象模型它把HTML文档表示为节点树,让我们可以用 JavaScript 操作这个树状结构,从而动态地改变网页的内容和外观

一、基础概念

在开始之前,我们需要理解几个关键概念:

  1. DOM树:HTML文档被浏览器解析为一个树状结构,每个标签、属性、文本都是一个节点

  2. 节点类型:主要有元素节点①、属性节点②、文本节点③等

  3. 节点关系:父子(parent-child)、兄弟(sibling)关系

 二、节点获取

1. 传统方法

  • getElementById() 方法:通过元素的 id 属性值获取唯一的元素对象;
  • getElementsByClassName() 方法:通过元素的 class 属性值获取元素对象,返回相应的元素集合;
  • getElementsByName() 方法:通过元素的name属性值获取元素对象,返回相应的元素集合;
  • getElementsByTagName() 方法:通过元素类型获取元素对象,返回相应的元素集合,如 document.getElementsByTagName("p") 获取所有段落元素;
// 通过ID获取
const element = document.getElementById('myId');

// 通过类名获取(返回HTMLCollection)
const elements = document.getElementsByClassName('myClass');

// 通过标签名获取(返回HTMLCollection)
const divs = document.getElementsByTagName('div');

// 通过name属性获取(常用于表单元素)
const inputs = document.getElementsByName('username');

其中,由于ID在HTML文档中是唯一的,所以document.getElementById()可以直接定位唯一的一个DOM节点。

2. 现代方法(推荐) 

// 查询单个元素(返回第一个匹配的元素)
const el = document.querySelector('.my-class');

// 查询多个元素(返回NodeList)
const els = document.querySelectorAll('div.note');

 3. 特殊选择

// 获取文档根元素
const html = document.documentElement;

// 获取body元素
const body = document.body;

// 获取head元素
const head = document.head;

小案例1:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style></style>
</head>

<body>
    <h1 id="MyName">Yuki</h1>
</body>
<script>
    const nameElement = document.getElementById('MyName');  // 获取元素

    nameElement.addEventListener('click', () => {
        nameElement.style.color = 'blue';
        nameElement.style.fontSize = '24px';
        nameElement.style.fontWeight = 'bold';
        nameElement.textContent = 'Yuki - 你点击了我!';
    })
</script>
</html>

注意点:

这个案例中,我们发现在CSS中font-size这样的名称,却在JavaScript中不是有效的属性名,所以需要在JavaScript中改写为驼峰式命名fontSize 


小案例2:

跟id的唯一性不同的是,页面中的多个元素可能使用相同的 class 属性值,这时候获取这些元素时可以使用 document.getElementsByClassName() 方法,前面说过,它会返回一个由这些元素组成的集合

<!DOCTYPE html>
<html>
<head>
    <title>getElementsByClassName案例</title>
    <style>
        .highlight {
            padding: 10px;
            margin: 5px;
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <div class="highlight">第一个高亮元素</div>
    <div class="highlight">第二个高亮元素</div>
    <div class="highlight">第三个高亮元素</div>
    <button id="changeColorBtn">改变所有高亮元素颜色</button>

    <script>
        const changeBtn = document.getElementById('changeColorBtn');
        
        changeBtn.addEventListener('click', function() {
            // 获取所有class为highlight的元素
            const highlights = document.getElementsByClassName('highlight');
            
            // 遍历并修改每个元素的样式
            for (let i = 0; i < highlights.length; i++) {
                highlights[i].style.backgroundColor = getRandomColor();
                highlights[i].style.color = 'white';
                highlights[i].style.fontWeight = 'bold';
            }
        });

        // 生成随机颜色函数(这个函数可以暂时不管,只是为了辅助理解,可以自行搜索代码解析)
        function getRandomColor() {
            // letters包含了十六进制颜色中可能用到的所有字符:0-9 数字和 A-F 字母(共 16 个字符)
            const letters = '0123456789ABCDEF';
            let color = '#';           // 十六进制颜色的前缀标识
            // 使用 for 循环执行 6 次(因为十六进制颜色由 6 个字符组成)
            for (let i = 0; i < 6; i++) {
                color += letters[Math.floor(Math.random() * 16)];
            }
            return color;  // 返回生成的随机颜色,如 #3A7F9D
        }
    </script>
</body>
</html>

※代码解析

  1. 我们创建了3个具有相同class="highlight"的div元素

  2. 点击按钮时,使用getElementsByClassName获取所有高亮元素

  3. 遍历返回的HTMLCollection,为每个元素设置随机背景色

  4. 注意HTMLCollection是"动态的",会实时反映DOM变化(点击会实时变化颜色,如下图)

 


小案例3:

注意getElementsByClassNamegetElementsByTagName返回的是动态集合(HTMLCollection),而querySelectorAll返回的是静态集合(NodeList)

案例2感受到了getElementsByClassName的动态,那么这个静态怎么理解?来个小案例感受下对比吧!

<!DOCTYPE html>
<html>
<head>
    <title>动态vs静态集合</title>
</head>
<body>
    <div class="box">盒子1</div>
    <div class="box">盒子2</div>
    <button id="addBoxBtn">添加盒子</button>
    <button id="showBoxCountBtn">显示盒子数量</button>

    <script>
        const addBoxBtn = document.getElementById('addBoxBtn');
        const showBoxCountBtn = document.getElementById('showBoxCountBtn');
        let boxCount = 3; // 初始盒子数量

        // 两种方式获取元素
        const boxesHTMLCollection = document.getElementsByClassName('box');
        console.log('初始HTMLCollection长度:', boxesHTMLCollection.length);

        const boxesNodeList = document.querySelectorAll('.box');
        console.log('初始NodeList长度:', boxesNodeList.length);

        // 添加新盒子
        addBoxBtn.addEventListener('click', () => {
            const newBox = document.createElement('div'); // 这个创建节点在下面会讲
            newBox.className = 'box';
            newBox.textContent = `盒子${boxCount++}`;
            document.body.appendChild(newBox);
        });

        // 显示盒子数
        showBoxCountBtn.addEventListener('click', () => {
            console.log('当前HTMLCollection长度:', boxesHTMLCollection.length);
            console.log('当前NodeList长度:', boxesNodeList.length);
            alert(`HTMLCollection长度: ${boxesHTMLCollection.length}, NodeList长度: ${boxesNodeList.length}`);
            // 注意:boxesHTMLCollection是动态的,会自动更新
            // boxesNodeList是静态的,不会自动更新
        });
    </script>
</body>
</html>

先看运行结果感受下:

点击添加盒子,随便点击几次,然后点击显示盒子数量,可以看到: 

关键区别

  • getElementsByClassName返回的HTMLCollection是动态的,会随DOM变化自动更新,每次添加新元素后,length会自动增加

  • querySelectorAll返回的NodeList是静态的,不会反映之后的DOM变化

  • 在需要实时获取最新元素集合时,使用getElementsByClassName更合适


三、节点创建

1. 创建元素节点

// 创建一个div元素
const newDiv = document.createElement('div');

// 创建一个文本节点
const newText = document.createTextNode('你好,世界!');

// 创建一个注释节点
const newComment = document.createComment('这是一个注释');

这一块上面的案例3就有涉及到,可以回过头去看看~~

 2. 克隆节点

const original = document.querySelector('.original');
const cloned = original.cloneNode(true); // true表示深克隆(包括子节点)

深入了解可到:插入DOM - JavaScript教程 - 廖雪峰的官方网站 


四、节点修改

1. 修改内容

// 方法一:修改HTML内容(会解析HTML标签)
element.innerHTML = '<strong>新内容</strong>';

// 方法二:修改文本内容(不会解析HTML标签)
element.innerText = '纯文本内容';
element.textContent = '纯文本内容';

// 修改value(表单元素)
input.value = '新的值';

注意1:其中,innerText 属性将内容当作文本处理,而 innerHTML 属性则将内容解析为 HTML 代码,可以使用标签生成页面元素。 

怎么理解这句话?来个小案例感受下:

小案例1:

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<p id="p1">段落一</p>
<p id="p2">段落二</p>
</body>
</html>
<script>
    var p1 = document.getElementById("p1");
    var p2 = document.getElementById("p2");
    var s = "<b>加粗文本</b>";
    p1.innerText += s;
    p2.innerHTML += s;
</script>

可以看到,段落一是使用的 innerText 去获取的,不管你<b>标签的用法,当纯文本。

而段落二是 innerHTML ,会把<b>标签识别为html代码。


注意2为什么方式二有两种: innerText 和 textContent ?——核心区别:是否返回隐藏元素的文本(另外注意IE<9不支持textContent

怎么理解?

  • innerText:获取元素文本时,会忽略页面中被 CSS 隐藏的元素(比如设置了 display: none 或 visibility: hidden 的元素),只返回用户在页面上能实际看到的文本内容。
  • textContent:则会返回元素中所有文本内容,无论这些文本所在的元素是否被隐藏,包括通过 CSS 隐藏的元素中的文本。

照旧,来个案例感受:

小案例2:

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
    <div id="test">
        可见文本
        <span style="display: none;">隐藏文本</span>
    </div>
</body>
</html>
<script>
    var test = document.getElementById("test").textContent;
    console.log(test); 
    var test2 = document.getElementById("test").innerText;
    console.log(test2); 
</script>

2. 修改属性

// 设置属性
element.setAttribute('id', 'newId');

// 获取属性
const id = element.getAttribute('id');

// 移除属性
element.removeAttribute('id');

// 检查是否有某属性
const hasAttr = element.hasAttribute('id');

// class操作
element.classList.add('new-class');
element.classList.remove('old-class');
element.classList.toggle('active');

3. 修改样式

// 直接修改style属性
element.style.color = 'red';
element.style.backgroundColor = '#f0f0f0';

// 批量修改样式
Object.assign(element.style, {
  color: 'blue',
  fontSize: '16px',
  display: 'none'
});

 五、节点删除

1. 移除节点

// 方法1:通过父节点移除子节点
// 解析:要删除一个节点,首先要获得该节点本身以及它的父节点,然后,调用父节点的removeChild把自己删掉 
const parent = document.getElementById('parent');
const child = document.getElementById('child');
parent.removeChild(child);

// 方法2:直接移除自己(较新方法)
child.remove();

 2. 替换节点

const oldNode = document.getElementById('old');
const newNode = document.createElement('div');
newNode.textContent = '我是新节点';

// 通过父节点替换
oldNode.parentNode.replaceChild(newNode, oldNode);

// 或者使用replaceWith方法
oldNode.replaceWith(newNode);

 六、节点关系

1. 父子关系

// 获取父节点
const parent = child.parentNode; // 或 parentElement

// 获取所有子节点(包括文本节点等)
const allChildren = parent.childNodes;

// 获取子元素(仅元素节点)
const children = parent.children;

// 第一个子节点
const firstChild = parent.firstChild;

// 最后一个子节点
const lastChild = parent.lastChild;

2. 兄弟关系

// 上一个兄弟节点
const prevSibling = element.previousSibling;

// 下一个兄弟节点
const nextSibling = element.nextSibling;

// 上一个兄弟元素节点
const prevElementSibling = element.previousElementSibling;

// 下一个兄弟元素节点
const nextElementSibling = element.nextElementSibling;

 七、实践案例:

练习1:创建一个评论列表

<!DOCTYPE html>
<html>
<head>
    <title>评论列表</title>
    <style>
        .comment {
            border: 1px solid #ddd;
            padding: 10px;
            margin: 10px 0;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div id="comments-container"></div>
    <button id="add-comment-btn">添加评论</button>

    <script>
        const container = document.getElementById('comments-container');
        const btn = document.getElementById('add-comment-btn');
        let counter = 1;

        btn.addEventListener('click', () => {
            // 创建评论元素
            const comment = document.createElement('div');
            comment.className = 'comment';
            
            // 创建评论内容
            const content = document.createElement('p');
            content.textContent = `这是第${counter++}条评论`;
            
            // 创建删除按钮
            const deleteBtn = document.createElement('button');
            deleteBtn.textContent = '删除';
            deleteBtn.addEventListener('click', () => {
                comment.remove();
            });
            
            // 组装评论
            comment.appendChild(content);
            comment.appendChild(deleteBtn);
            
            // 添加到容器
            container.appendChild(comment);
        });
    </script>
</body>
</html>

八、尾声:

JavaScript 中的 DOM 操作——面向初学者的全面指南

操作DOM - JavaScript教程 - 廖雪峰的官方网站

DOM 概述 - Web API | MDN

JavaScript DOM操作详解(附带实例) - C语言中文网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值