【零基础JavaScript入门 | Day7】三大交互案例深度解析|从DOM操作到组件化开发
🌟今日知识图谱:
✅ 事件驱动编程 → 按钮交互与定时器控制
✅ 组件化思维 → 可复用UI模块开发
✅ 用户体验优化 → 动画与状态反馈设计
✅ 工程化实践 → 代码组织与维护技巧
案例一:课堂点名小助手
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}h2 {text-align: center;}.box {width: 600px;margin: 50px auto;display: flex;}.qs {width: 450px;height: 40px;color: red;}.btns {text-align: center;}.btns button {width: 100px;height: 35px;margin: 0 40px;}</style>
</head><body><h2>随机点名</h2><div class="box"><span>名字是:</span><div class="qs">这里显示姓名</div></div><div class="btns"><button class="start">开始</button><button class="end">结束</button></div><script>const arr = ['张三', '李四', '王五', '赵六', '田七', '王八', '陈九', '韩十']// 获取对象const qs = document.querySelector('.qs')const start = document.querySelector('.start')// 定时器的全局变量let n = null// 声明全局变量let random = null//添加点击事件start.addEventListener('click', function () {n = setInterval(function () {const random = Math.floor(Math.random() * arr.length)qs.innerHTML = arr[random]}, 100)// 如果数组里面只剩一个,不需要抽取if (arr.length === 1) {start.disabled = trueend.disabled = true}})// 关闭点击模块const end = document.querySelector('.end')end.addEventListener('click', function () {clearInterval(n)arr.splice(random, 1)console.log(arr)})</script>
</body></html>
🔍 功能升级建议:
- 音效增强:添加点击音效(
audio.play()
) - 动画效果:名字滚动时添加CSS旋转动画
- 数据持久化:
localStorage
保存剩余名单
案例二:智能搜索提示框
<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><title>小米搜索框练习模板</title><style>/* 容器样式 */.search-box {margin: 100px auto;width: 500px;text-align: center;}/* 搜索容器(包含输入框和图标的父元素) */.search-container {position: relative;display: inline-block;}/* 默认输入框样式 */.search-input {width: 100px;/* 默认宽度 */height: 35px;padding: 0 30px;border: 1px solid #e0e0e0;border-radius: 17px;outline: none;transition: all 0.3s;/* 添加过渡动画 */}/* 搜索图标样式 */.search-icon {position: absolute;left: 10px;top: 50%;transform: translateY(-50%);width: 18px;height: 18px;background: url('data:image/svg+xml;utf8,<svg fill="#999999" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M945.066667 898.133333l-147.2-147.2c44.8-32 83.2-72.533333 108.8-121.6 34.133333-57.6 51.2-121.6 51.2-185.6 0-164.266667-134.4-300.8-300.8-300.8-166.4 0-300.8 134.4-300.8 300.8s134.4 300.8 300.8 300.8c61.866667 0 123.733333-19.2 174.933333-53.333333 44.8-32 83.2-72.533333 108.8-121.6l147.2 147.2c6.4 6.4 14.933333 8.533333 23.466667 8.533333s17.066667-2.133333 23.466666-8.533333c10.666667-12.8 10.666667-34.133333-2.133333-46.933334zM460.8 742.4c-151.466667 0-275.2-123.733333-275.2-275.2s123.733333-275.2 275.2-275.2 275.2 123.733333 275.2 275.2-123.733333 275.2-275.2 275.2z"/></svg>');pointer-events: none;}.result-list {display: none;list-style: none;padding: 0;margin: 0;position: absolute;top: 100%;left: 0;width: 100%;background-color: #fff;border: 1px solid #ccc;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);}.result-list a {text-decoration: none;color: #333;display: block;padding: 5px;border-bottom: 1px solid #ccc;cursor: pointer;}.result-list a:hover {background-color: #f0f0f0;}</style>
</head><body><!-- 搜索框结构 --><div class="search-box"><div class="search-container"><!-- 输入框 --><input type="text" class="search-input" placeholder="搜索内容"><ul class="result-list"><li><a href="#">全部商品</a></li><li><a href="#">小米15</a></li><li><a href="#">小米14</a></li><li><a href="#">红米k60</a></li><li><a href="#">小米笔记本</a></li><li><a href="#">小米15ultra</a></li><li><a href="#">小米14pro</a></li></ul></div></div><script>// 获取元素const input = document.querySelector('.search-input');const ul = document.querySelector('.result-list');const searchContainer = document.querySelector('.search-container');// 监听事件,获得焦点input.addEventListener('focus', function () {ul.style.display = 'block';})// 监听事件,失去焦点input.addEventListener('blur', function () {ul.style.display = 'none';})</script>
</body></html>
✨ 新增功能模块:
- 热门搜索标签:展示本周Top5搜索词
- 历史记录:自动保存最近10条搜索记录
- 键盘导航:方向键选择建议项
案例三:交互式轮播组件
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>轮播图点击切换</title><style>* {box-sizing: border-box;}.slider {width: 240px;height: 450px;overflow: hidden;}.slider-poster {width: 100%;height: 320px;}.slider-poster img {width: 100%;height: 100%;display: block;}.slider-footer {height: 80px;background-color: rgb(100, 67, 68);padding: 12px 12px 0 12px;position: relative;}.slider-footer .toggle {position: absolute;right: 0;top: 12px;display: flex;}.slider-footer .toggle button {margin-right: 12px;width: 28px;height: 28px;appearance: none;border: none;background: rgba(255, 255, 255, 0.1);color: #fff;border-radius: 4px;cursor: pointer;}.slider-footer .toggle button:hover {background: rgba(255, 255, 255, 0.2);}.slider-footer p {margin: 0;color: #fff;font-size: 18px;margin-bottom: 10px;}.slider-indicator {margin: 0;padding: 0;list-style: none;display: flex;align-items: center;}.slider-indicator li {width: 8px;height: 8px;margin: 4px;border-radius: 50%;background: #fff;opacity: 0.4;cursor: pointer;}.slider-indicator li.active {width: 12px;height: 12px;opacity: 1;}</style>
</head><body><div class="slider"><div class="slider-poster"><img src="./images/p1.jpg" alt="" /></div><div class="slider-footer"><p>魔法石</p><ul class="slider-indicator"><li class="active"></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><div class="toggle"><button class="prev"><</button><button class="next">></button></div></div></div><script>// 1. 初始数据const pData = [{ url: './images/p1.jpg', title: '魔法石', color: 'rgb(36, 156, 200)' },{ url: './images/p2.jpg', title: '密室', color: 'rgb(43, 35, 26)' },{ url: './images/p3.jpg', title: '阿兹卡班的囚徒', color: 'rgb(36, 31, 33)' },{ url: './images/p4.jpg', title: '火焰杯', color: 'rgb(45, 110, 113)' },{ url: './images/p5.jpg', title: '凤凰社', color: 'rgb(67, 90, 92)' },{ url: './images/p6.jpg', title: '死亡圣器(上)', color: 'rgb(7, 66, 73)' },{ url: './images/p7.jpg', title: '死亡圣器(下)', color: 'rgb(53, 29, 25)' },]// 获取对象const img = document.querySelector('.slider-poster img')const footer = document.querySelector('.slider-footer')const p = document.querySelector('.slider-footer p')const next = document.querySelector('.next')let i = 0next.addEventListener('click', function () {i++if (i === pData.length) {i = 0}img.src = pData[i].urlfooter.style.backgroundColor = pData[i].colorp.innerHTML = pData[i].titledocument.querySelector('.slider-indicator .active').classList.remove('active')document.querySelector(`.slider-indicator li:nth-child(${i + 1})`).classList.add('active')})const prev = document.querySelector('.prev')prev.addEventListener('click', function () {i--if (i <= -1) {i = 6}common()})function common() {img.src = pData[i].urlfooter.style.backgroundColor = pData[i].colorp.innerHTML = pData[i].titledocument.querySelector('.slider-indicator .active').classList.remove('active')document.querySelector(`.slider-indicator li:nth-child(${i + 1})`).classList.add('active')}// 自动播放let n = setInterval(function () {next.click()}, 1000)// 鼠标经过盒子时,停止播放const slider = document.querySelector('.slider')slider.addEventListener('mouseenter', function () {clearInterval(n)})// 鼠标离开盒子时,继续播放slider.addEventListener('mouseleave', function () {n = setInterval(function () {next.click()}, 1000)})</script></body></html>
🚀 企业级优化:
- 无限循环模式:克隆首尾元素实现无缝滚动
🎯 共性优化策略
优化方向 | 案例一 | 案例二 | 案例三 |
---|---|---|---|
代码结构 | 减少全局变量 | 模块化封装 | 类组件化 |
用户体验 | 添加加载动画 | 输入防抖 | 滑动过渡 |
功能扩展 | 名单导入导出 | 搜索联想 | 缩略图导航 |
📌 注意事项:
- 所有修改需保持原始HTML结构
- 优先使用
textContent
替代innerHTML
防XSS攻击 - 定时器务必及时清理(
clearInterval
)