JavaScript 从零基础到精通系列:DOM 操作与事件驱动编程

摘要: JavaScript 在浏览器中的魔法,几乎全部通过 DOM 实现。本篇将学会如何选取页面元素,动态修改内容和样式,并深刻理解事件模型(事件冒泡、委托)。你将亲手打造图片轮播器和留言板,把前几篇的数据逻辑变成用户看得见、摸得着的交互界面。


一、认识 DOM

DOM(Document Object Model)是浏览器将 HTML 文档解析成的一个树形对象模型。每个标签、属性、文本都是树上的一个节点。JavaScript 可以访问、修改、添加、删除这些节点,从而动态改变页面。根节点是 document,代表整个页面。

二、获取元素

最常用的几个方法:

javascript 复制代码
// 通过 ID
const header = document.getElementById('main-header');
// 通过 CSS 选择器(返回第一个匹配)
const btn = document.querySelector('.btn-primary');
// 通过 CSS 选择器(返回所有匹配,NodeList 静态或动态取决于方法)
const items = document.querySelectorAll('.item');
// 通过类名
const errors = document.getElementsByClassName('error');

querySelectorquerySelectorAll 使用 CSS 选择器语法,灵活强大,是现在的主流选择方式。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>DOM 选择器测试</title>
    <style>
        /* 给元素加点样式方便看 */
        #main-header { color: blue; font-size: 20px; }
        .btn-primary { background: green; color: white; padding: 5px; }
        .item { margin: 5px; border: 1px solid #ccc; }
        .error { color: red; font-weight: bold; }
    </style>
</head>
<body>

    <!-- 我们要获取的元素都在这里 -->
    <h1 id="main-header">我是 ID 为 main-header 的标题</h1>
    <button class="btn-primary">我是 class 为 btn-primary 的按钮</button>
    <ul>
        <li class="item">列表项 1</li>
        <li class="item">列表项 2</li>
        <li class="item error">列表项 3(带 error)</li>
    </ul>

<script>
// ======================
// 1. 通过 ID 获取
// ======================
const header = document.getElementById('main-header');
console.log("通过 ID 获取:", header); // 看控制台!
header.style.color = "red"; // 把文字变红 → 页面能看到效果!


// ======================
// 2. 通过 CSS 选择器(单个)
// ======================
const btn = document.querySelector('.btn-primary');
console.log("通过选择器获取按钮:", btn);
btn.innerText = "我被修改啦!"; // 修改按钮文字 → 页面能看到!


// ======================
// 3. 获取所有 .item
// ======================
const items = document.querySelectorAll('.item');
console.log("所有列表项:", items);

// 循环修改所有 item
items.forEach((item, index) => {
    item.innerText = `我是第 ${index+1} 个 item`;
});


// ======================
// 4. 通过 class 获取
// ======================
const errors = document.getElementsByClassName('error');
console.log("错误元素:", errors[0]);
errors[0].innerText = "我是错误提示!";

</script>
</body>
</html>

三、修改内容与属性

  • textContent:纯文本,不解析 HTML。

  • innerHTML:会解析 HTML 标签,有安全风险(XSS),插入用户输入时慎用。

  • value:表单元素的值。

javascript 复制代码
const title = document.querySelector('h1');
title.textContent = '新标题';
​
const link = document.querySelector('a');
link.setAttribute('href', 'https://example.com');
link.getAttribute('href');
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <title>DOM 修改测试</title>
</head>

<body>

    <!-- 必须要有这两个元素,JS 才能找到它们 -->
    <h1>旧标题</h1>
    <a>我是链接</a>

    <script>
        // 1. 修改标题文字
        const title = document.querySelector('h1');
        title.textContent = '新标题'; // 页面会立刻变成"新标题"

        // 2. 修改链接地址
        const link = document.querySelector('a');
        link.setAttribute('href', 'https://example.com');

        // 3. 获取链接地址并打印(这样才能看到效果)
        const hrefValue = link.getAttribute('href');
        console.log('链接地址是:', hrefValue); // 控制台会输出 https://example.com

        // 给链接加点文字,方便看
        link.textContent = "点我去 example.com";
    </script>

</body>

</html>

样式修改:通过 element.style 修改内联样式,或通过 classList 增删类名(推荐)。

javascript 复制代码
const box = document.querySelector('.box');
box.style.backgroundColor = 'lightblue';
​
// classList 方法
box.classList.add('active');
box.classList.remove('hidden');
box.classList.toggle('dark-mode');
box.classList.contains('active'); // true/false
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>classList + style 测试</title>
    <style>
        /* 必须先定义 .box 样式 */
        .box {
            width: 200px;
            height: 200px;
            margin: 20px;
            border: 1px solid #333;
        }
        /* 下面是 JS 会操作的 class */
        .active {
            border: 4px solid red;
        }
        .hidden {
            display: none;
        }
        .dark-mode {
            background-color: #333;
            color: white;
        }
    </style>
</head>
<body>

    <!-- 这个元素就是 JS 要找的 .box -->
    <div class="box">我是盒子</div>

<script>
    const box = document.querySelector('.box');

    // 1. 直接修改样式:背景变浅蓝色
    box.style.backgroundColor = 'lightblue';

    // 2. 添加 class → 出现红边框
    box.classList.add('active');

    // 3. 移除 class(这里本来没有,所以没变化)
    box.classList.remove('hidden');

    // 4. 切换 class(有就删,没有就加)
    box.classList.toggle('dark-mode');

    // 5. 判断是否包含某个 class → 打印到控制台
    const hasActive = box.classList.contains('active');
    console.log('是否包含 active:', hasActive); // true
</script>

</body>
</html>

四、事件监听:让页面响应用户

事件是用户或浏览器自身发生的动作,如点击、移动、键盘、加载等。

javascript 复制代码
const button = document.getElementById('myBtn');
​
// 推荐方式:addEventListener
button.addEventListener('click', function(event) {
    console.log('按钮被点击了', event);
    // event.target 是触发事件的元素
});
​
// 匿名函数或具名函数都可以
function handleMouseEnter(e) {
    console.log('鼠标进来了');
}
button.addEventListener('mouseenter', handleMouseEnter);
// 移除监听
button.removeEventListener('mouseenter', handleMouseEnter);
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>事件监听测试</title>
    <style>
        #myBtn {
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
        }
    </style>
</head>
<body>

    <!-- 必须有这个按钮,JS 才能找到它 -->
    <button id="myBtn">点我测试</button>

<script>
    const button = document.getElementById('myBtn');

    // 1. 点击事件
    button.addEventListener('click', function(event) {
        console.log('✅ 按钮被点击了', event);
        alert('你点击了按钮!');
    });

    // 2. 鼠标移入事件
    function handleMouseEnter(e) {
        console.log('🐭 鼠标进来了');
        button.style.background = "lightgreen";
    }

    // 绑定鼠标移入
    button.addEventListener('mouseenter', handleMouseEnter);

    // 注意:我先注释掉移除,不然刚绑定就删了,没效果!
    // button.removeEventListener('mouseenter', handleMouseEnter);
</script>
</body>
</html>

常见事件类型:

  • 鼠标:click, dblclick, mousedown, mouseup, mousemove, mouseenter, mouseleave

  • 键盘:keydown, keyup, keypress(已废弃,建议 keydown)

  • 表单:submit, change, input, focus, blur

  • 文档/窗口:DOMContentLoaded, load, resize, scroll

五、事件流:捕获与冒泡及事件委托

当一个元素触发事件,它会经历三个阶段:

捕获阶段:从 window 向目标元素向下传播。

目标阶段:事件到达目标元素。

冒泡阶段:事件从目标元素向上冒泡到 window

addEventListener 的第三个参数默认 false(在冒泡阶段处理)。利用冒泡可以实现事件委托 :把监听器绑定在父元素上,通过 event.target 识别实际点击的子元素。这样可以大幅减少监听器数量,且动态添加的子元素也能自动拥有此行为。

javascript 复制代码
// 列表委托
const list = document.querySelector('#myList');
list.addEventListener('click', function(e) {
    if (e.target.tagName === 'LI') {
        console.log('你点击了', e.target.textContent);
    }
});
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>事件委托测试</title>
    <style>
        li {
            padding: 8px 12px;
            margin: 5px 0;
            background: #f1f1f1;
            cursor: pointer;
        }
        li:hover {
            background: lightblue;
        }
    </style>
</head>
<body>

    <!-- 必须有这个列表,JS 才能生效 -->
    <ul id="myList">
        <li>我是第 1 项</li>
        <li>我是第 2 项</li>
        <li>我是第 3 项</li>
        <li>我是第 4 项</li>
    </ul>

<script>
    // 事件委托:只给父 ul 绑定事件
    const list = document.querySelector('#myList');
    
    list.addEventListener('click', function(e) {
        // 判断点击的是不是 LI 元素
        if (e.target.tagName === 'LI') {
            console.log('你点击了:', e.target.textContent);
            
            // 可选:页面弹出提示,更直观
            alert('你点击了:' + e.target.textContent);
        }
    });
</script>
</body>

六、动态创建与删除元素

javascript 复制代码
// 创建一个新 div
const newDiv = document.createElement('div');
newDiv.textContent = '我是新来的';
newDiv.classList.add('box');
// 追加到父元素末尾
document.body.appendChild(newDiv);
​
// 在前面插入
const referenceNode = document.querySelector('#ref');
document.body.insertBefore(newDiv, referenceNode);
​
// 删除元素
newDiv.remove();

七、表单操作与定时器

获取表单数据:

javascript 复制代码
const form = document.querySelector('#userForm');
form.addEventListener('submit', function(e) {
    e.preventDefault(); // 阻止默认提交刷新页面
    const username = document.querySelector('#username').value;
    console.log('提交的用户名:', username);
});
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>表单提交测试</title>
    <style>
        form {
            margin: 20px;
            padding: 15px;
            border: 1px solid #ccc;
            display: inline-block;
        }
        input {
            padding: 8px;
            margin-right: 5px;
        }
        button {
            padding: 8px 12px;
            cursor: pointer;
        }
    </style>
</head>
<body>

    <!-- 必须有这个表单,JS 才能生效 -->
    <form id="userForm">
        <input type="text" id="username" placeholder="请输入用户名">
        <button type="submit">提交</button>
    </form>

<script>
const form = document.querySelector('#userForm');

form.addEventListener('submit', function(e) {
    // 阻止页面自动刷新(最关键!)
    e.preventDefault();
    
    // 获取输入框的值
    const username = document.querySelector('#username').value;
    
    // 控制台打印 + 页面提示
    console.log('提交的用户名:', username);
    alert('你提交了:' + username);
});
</script>
</body>
</html>

定时器:

  • setTimeout(fn, delay):延迟执行一次。

  • setInterval(fn, interval):每隔一段时间重复执行。

  • clearTimeout / clearInterval 清除。

javascript 复制代码
// 简单计数器
let count = 0;
const timer = setInterval(() => {
    count++;
    console.log(count);
    if (count >= 5) clearInterval(timer);
}, 1000);

八、综合实战一:图片轮播器

实现一个简单的自动轮播,并带手动切换按钮。

HTML 结构:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <title>轮播图效果</title>
</head>

<body>

    <div class="slider">
        <div class="slides">
            <img src="https://picsum.photos/400/300?random=4" class="active" />
            <img src="https://picsum.photos/400/300?random=5" />
            <img src="https://picsum.photos/400/300?random=6" />
        </div>
        <button id="prev">←</button>
        <button id="next">→</button>
    </div>

</body>

</html>

CSS:

css 复制代码
.slider {
    position: relative;
    width: 400px;
    height: 300px;
    overflow: hidden;
    border: 2px solid #ccc;
}

.slides {
    width: 100%;
    height: 100%;
}

.slides img {
    position: absolute;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: none;
    /* 默认隐藏 */
}

.slides img.active {
    display: block;
    /* 只显示当前激活的 */
}
/* 按钮样式 */

#prev,
#next {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(0, 0, 0, 0.5);
    color: white;
    border: none;
    padding: 10px 15px;
    cursor: pointer;
    font-size: 18px;
    z-index: 10;
}

#prev {
    left: 10px;
}

#next {
    right: 10px;
}

JS 逻辑:

javascript 复制代码
(function() {
    const slides = document.querySelectorAll('.slides img');
    const prevBtn = document.getElementById('prev');
    const nextBtn = document.getElementById('next');
    let currentIndex = 0;

    function showSlide(index) {
        slides.forEach((slide, i) => {
            slide.classList.toggle('active', i === index);
        });
    }

    function nextSlide() {
        currentIndex = (currentIndex + 1) % slides.length;
        showSlide(currentIndex);
    }

    function prevSlide() {
        currentIndex = (currentIndex - 1 + slides.length) % slides.length;
        showSlide(currentIndex);
    }

    nextBtn.addEventListener('click', nextSlide);
    prevBtn.addEventListener('click', prevSlide);

    // 自动播放
    setInterval(nextSlide, 3000);
})();

九、综合实战二:简单留言板

结合数组、DOM 操作和事件。用户输入留言,点击发布后添加到列表,可删除。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>消息列表 - 新增/删除</title>
    <style>
        /* 简单美化,让效果更直观 */
        .container {
            width: 400px;
            margin: 30px auto;
        }
        #messageInput {
            width: 280px;
            padding: 8px;
        }
        #addBtn {
            padding: 8px 12px;
            cursor: pointer;
        }
        #messageList {
            margin-top: 15px;
            list-style: none;
            padding: 0;
        }
        #messageList li {
            padding: 10px;
            background: #f5f5f5;
            margin: 5px 0;
            display: flex;
            justify-content: space-between;
        }
        .delete {
            color: white;
            background: red;
            border: none;
            padding: 3px 6px;
            cursor: pointer;
        }
    </style>
</head>
<body>

    <!-- 配套 HTML 结构 -->
    <div class="container">
        <input type="text" id="messageInput" placeholder="请输入内容">
        <button id="addBtn">添加</button>
        <ul id="messageList"></ul>
    </div>

<script>
const input = document.querySelector('#messageInput');
const addBtn = document.querySelector('#addBtn');
const list = document.querySelector('#messageList');

// 添加消息
addBtn.addEventListener('click', function() {
    const text = input.value.trim();
    if (!text) return alert('内容不能为空');
    
    const li = document.createElement('li');
    li.innerHTML = `
        <span>${text}</span>
        <button class="delete">删除</button>
    `;
    list.appendChild(li);
    input.value = '';
    input.focus();
});

// 事件委托 - 删除
list.addEventListener('click', function(e) {
    if (e.target.classList.contains('delete')) {
        e.target.parentElement.remove();
    }
});
</script>
</body>
</html>

总结: DOM 是连接 JavaScript 和用户界面的桥梁。我们掌握了元素选取、内容样式修改、事件监听及事件委托,这些是任何前端项目 80% 的日常工作。通过轮播器和留言板,我们练习了动态节点创建、定时器和表单处理。


如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享 ,也可以留言告诉我你遇到的其它问题,我会尽快回复。动手练习是掌握编程最快的方法,请务必亲手敲一遍本文的所有示例代码,并截图保存你的成果。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。

相关推荐
零陵上将军_xdr1 小时前
后端转全栈学习-Day3-JavaScript 基础-1
开发语言·javascript·学习
GISHUB1 小时前
Express + TypeScript + ESM 后端服务搭建教程
javascript·typescript·express
ZC跨境爬虫1 小时前
跟着 MDN 学CSS day_32:(Web字体深度解析与实践指南)
前端·javascript·css·ui·html
sugar__salt2 小时前
JavaScript 数组去重全解:6 种核心方法
javascript
砍材农夫2 小时前
物联网 基于netty核心实战-安全tls
java·开发语言·前端·物联网·安全
SEO_juper2 小时前
JavaScript 渲染:AI 智能体无法读取,直接影响收录
开发语言·前端·javascript·aigc·seo·跨境电商·geo
whuhewei2 小时前
一道React缓存的题目
javascript·react.js
i220818 Faiz Ul2 小时前
在线预约导游|基于SSM+vue的在线预约导游系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·毕设·在线预约导游系统