【零基础JavaScript入门 | Day7】三大交互案例深度解析|从DOM操作到组件化开发
🌟今日知识图谱:
✅ 事件驱动编程 → 按钮交互与定时器控制
✅ 组件化思维 → 可复用UI模块开发
✅ 用户体验优化 → 动画与状态反馈设计
✅ 工程化实践 → 代码组织与维护技巧
案例一:课堂点名小助手
html
<!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 = true
end.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
保存剩余名单
案例二:智能搜索提示框
html
<!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条搜索记录
- 键盘导航:方向键选择建议项
案例三:交互式轮播组件
html
<!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 = 0
next.addEventListener('click', function () {
i++
if (i === pData.length) {
i = 0
}
img.src = pData[i].url
footer.style.backgroundColor = pData[i].color
p.innerHTML = pData[i].title
document.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].url
footer.style.backgroundColor = pData[i].color
p.innerHTML = pData[i].title
document.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
)