经过前 6 天的基础铺垫,今天我们将聚焦 Web 开发的核心链路:数据处理→DOM 操作→交互实现→数据持久化→表单验证。这是前端开发的 "闭环能力",也是从 "能写代码" 到 "能做项目" 的关键跨越。本文将通过 7 个递进式实战案例,帮你打通全链路技能。
一、JavaScript 数组操作:数据处理的核心能力
数组是处理数据的基础载体,无论是接口返回数据还是本地交互数据,都需要通过数组方法高效处理。
实战案例:待办事项数据管理(增删改查 + 筛选)
javascript
// 初始待办数据
let todos = [
{ id: 1, content: '学习数组方法', completed: false },
{ id: 2, content: '练习DOM操作', completed: true },
{ id: 3, content: '实现本地存储', completed: false }
];
// 1. 新增待办(push)
function addTodo(content) {
if (!content.trim()) return;
todos.push({
id: Date.now(), // 时间戳作为唯一ID
content,
completed: false
});
}
// 2. 删除待办(filter)
function deleteTodo(id) {
todos = todos.filter(todo => todo.id !== id);
}
// 3. 切换完成状态(map)
function toggleTodo(id) {
todos = todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
);
}
// 4. 筛选待办(filter)
function filterTodos(status) {
if (status === 'all') return [...todos];
if (status === 'active') return todos.filter(todo => !todo.completed);
if (status === 'completed') return todos.filter(todo => todo.completed);
}
// 测试
addTodo('学习本地存储');
toggleTodo(1);
console.log('筛选未完成:', filterTodos('active'));
核心方法解析:
push():尾部添加元素(适合新增数据)filter():筛选符合条件的元素(适合删除、筛选场景)map():批量处理元素(适合更新状态)- 扩展运算符
...:复制对象避免引用污染
二、DOM 基础全解析:页面渲染的核心逻辑
DOM 操作是数据可视化的桥梁,掌握 "数据→DOM" 的映射逻辑是前端开发的基本功。
实战案例:动态渲染待办列表(数据驱动 DOM)
html
<div class="todo-app">
<input type="text" id="todoInput" placeholder="请输入待办事项">
<button id="addBtn">添加</button>
<div class="filters">
<button data-filter="all">全部</button>
<button data-filter="active">未完成</button>
<button data-filter="completed">已完成</button>
</div>
<ul id="todoList"></ul>
</div>
<script>
// 承接上文的todos数组和方法
let currentFilter = 'all';
// 渲染函数:核心是将数组数据转化为DOM
function renderTodos() {
const todoList = document.getElementById('todoList');
const filteredTodos = filterTodos(currentFilter);
// 清空列表(避免重复渲染)
todoList.innerHTML = '';
// 遍历数据生成DOM
filteredTodos.forEach(todo => {
const li = document.createElement('li');
li.innerHTML = `
<input type="checkbox" ${todo.completed ? 'checked' : ''}
data-id="${todo.id}" class="toggle">
<span style="text-decoration: ${todo.completed ? 'line-through' : 'none'}">
${todo.content}
</span>
<button data-id="${todo.id}" class="delete">删除</button>
`;
todoList.appendChild(li);
});
}
// 初始渲染
renderTodos();
// 添加按钮事件(输入→新增→重新渲染)
document.getElementById('addBtn').addEventListener('click', () => {
const input = document.getElementById('todoInput');
addTodo(input.value);
input.value = '';
renderTodos(); // 关键:数据变化后重新渲染
});
</script>
DOM 操作核心逻辑:
- 定义
render()函数,作为数据→DOM 的映射入口 - 每次数据变化(增删改)后调用
render(),保证视图与数据一致 - 利用
data-*属性存储数据 ID,便于后续交互关联
三、事件监听与交互实现:让页面 "活" 起来
交互是前端的灵魂,通过事件监听将用户操作转化为数据变化,再通过渲染函数更新视图。
实战案例:待办列表交互功能完善
javascript
// 事件委托:利用父元素监听所有子元素事件(减少绑定次数)
document.getElementById('todoList').addEventListener('click', (e) => {
const target = e.target;
const id = Number(target.dataset.id); // 获取data-id并转为数字
// 1. 点击复选框切换状态
if (target.classList.contains('toggle')) {
toggleTodo(id);
renderTodos();
}
// 2. 点击删除按钮删除待办
if (target.classList.contains('delete')) {
deleteTodo(id);
renderTodos();
}
});
// 筛选按钮交互
document.querySelector('.filters').addEventListener('click', (e) => {
if (e.target.tagName === 'BUTTON') {
currentFilter = e.target.dataset.filter;
renderTodos(); // 切换筛选条件后重新渲染
}
});
事件监听技巧:
- 事件委托:将子元素事件绑定到父元素(如
ul监听li的点击),支持动态元素 dataset:通过data-*属性传递数据(如 ID、筛选条件),避免硬编码- 事件处理流程:用户操作→事件触发→数据更新→重新渲染
四、事件流与高效交互:解决复杂场景的交互冲突
事件流(捕获→目标→冒泡)是处理嵌套元素交互的关键,合理利用可避免冲突。
实战案例:弹窗组件的事件流控制
javascript
<div id="modal" style="display: none;">
<div class="modal-mask"></div>
<div class="modal-content">
<h3>编辑待办</h3>
<input type="text" id="editInput">
<button id="confirmBtn">确认</button>
<button id="cancelBtn">取消</button>
</div>
</div>
<script>
// 点击待办文本打开弹窗(新增事件委托逻辑)
document.getElementById('todoList').addEventListener('click', (e) => {
if (e.target.tagName === 'SPAN') {
const id = Number(e.target.parentNode.dataset.id);
const todo = todos.find(t => t.id === id);
document.getElementById('editInput').value = todo.content;
document.getElementById('modal').style.display = 'block';
// 确认编辑(利用事件冒泡,点击确认后关闭弹窗)
document.getElementById('confirmBtn').onclick = () => {
todo.content = document.getElementById('editInput').value;
document.getElementById('modal').style.display = 'none';
renderTodos();
};
}
});
// 点击遮罩层关闭弹窗
document.querySelector('.modal-mask').addEventListener('click', () => {
document.getElementById('modal').style.display = 'none';
});
// 关键:阻止弹窗内容区的事件冒泡(避免点击内部触发遮罩层关闭)
document.querySelector('.modal-content').addEventListener('click', (e) => {
e.stopPropagation();
});
</script>
事件流应用:
e.stopPropagation():阻止事件冒泡(如弹窗内容区点击不触发遮罩层事件)- 事件冒泡利用:子元素事件可被父元素捕获(如弹窗按钮点击可被外层监听)
五、DOM 进阶与日期对象:增强页面信息展示
结合日期对象可实现动态时间展示,提升页面实用性。
实战案例:显示待办创建时间
javascript
// 改造addTodo方法,添加创建时间
function addTodo(content) {
if (!content.trim()) return;
todos.push({
id: Date.now(),
content,
completed: false,
createTime: new Date() // 记录创建时间
});
}
// 改造renderTodos,显示格式化时间
function renderTodos() {
// ... 省略部分代码
filteredTodos.forEach(todo => {
// 格式化时间:YYYY-MM-DD HH:MM
const timeStr = `${todo.createTime.getFullYear()}-${
String(todo.createTime.getMonth() + 1).padStart(2, '0')}-${
String(todo.createTime.getDate()).padStart(2, '0')} ${
String(todo.createTime.getHours()).padStart(2, '0')}:${
String(todo.createTime.getMinutes()).padStart(2, '0')
}`;
li.innerHTML = `
<!-- 省略其他内容 -->
<span class="time">创建于:${timeStr}</span>
`;
});
}
日期对象常用方法:
getFullYear():获取年份getMonth():获取月份(0-11,需 + 1)padStart(2, '0'):补零处理(如 3→"03")
六、本地存储 + BOM 操作:解决数据丢失痛点
页面刷新后数据丢失是常见问题,localStorage可实现数据持久化,结合 BOM 操作优化体验。
实战案例:待办数据持久化存储
javascript
// 1. 从localStorage加载数据
function loadTodos() {
const saved = localStorage.getItem('todos');
if (saved) {
// 注意:localStorage存储的是字符串,需解析为对象,且日期需重新实例化
todos = JSON.parse(saved).map(todo => ({
...todo,
createTime: new Date(todo.createTime)
}));
}
}
// 2. 保存数据到localStorage
function saveTodos() {
localStorage.setItem('todos', JSON.stringify(todos));
}
// 3. 改造所有修改数据的方法,添加保存逻辑
function addTodo(content) {
// ... 原有逻辑
saveTodos(); // 新增后保存
}
function deleteTodo(id) {
// ... 原有逻辑
saveTodos(); // 删除后保存
}
// 4. 页面加载时自动加载数据
window.addEventListener('load', () => {
loadTodos();
renderTodos();
});
// 5. BOM操作:监听页面关闭事件提示
window.addEventListener('beforeunload', (e) => {
e.preventDefault();
e.returnValue = '确定要离开吗?未完成的待办会自动保存';
});
本地存储要点:
localStorage只能存储字符串,需用JSON.stringify()/JSON.parse()转换- 日期对象序列化后会变为字符串,需重新实例化
new Date() window.onload:页面加载完成后执行初始化操作
七、正则表达式:表单验证实战
表单验证是前端必备能力,正则表达式可高效验证输入合法性。
实战案例:待办输入框验证
html
<!-- 改造输入框,添加验证提示 -->
<input type="text" id="todoInput" placeholder="请输入待办事项(至少3个字符,不包含特殊符号)">
<p id="errorMsg" style="color: red; display: none;"></p>
<script>
// 验证待办内容的正则:仅允许中英文、数字、空格和常见标点
const todoReg = /^[\u4e00-\u9fa5a-zA-Z0-9\s,.,。]{3,}$/;
// 改造添加按钮事件,加入验证
document.getElementById('addBtn').addEventListener('click', () => {
const input = document.getElementById('todoInput');
const errorMsg = document.getElementById('errorMsg');
const content = input.value.trim();
if (!todoReg.test(content)) {
errorMsg.textContent = '请输入至少3个字符,且不包含特殊符号';
errorMsg.style.display = 'block';
return;
}
// 验证通过,隐藏错误提示
errorMsg.style.display = 'none';
addTodo(content);
input.value = '';
renderTodos();
});
// 输入时实时验证
document.getElementById('todoInput').addEventListener('input', (e) => {
const errorMsg = document.getElementById('errorMsg');
if (todoReg.test(e.target.value.trim())) {
errorMsg.style.display = 'none';
}
});
</script>
正则表达式解析:
^[\u4e00-\u9fa5]:匹配中文字符a-zA-Z0-9:匹配英文和数字\s,.,。:匹配空格和常见标点{3,}:至少 3 个字符test():检测字符串是否符合正则规则
总结:全链路开发思维
今天的实战案例围绕 "待办应用" 展开,串联了 7 大核心技能:
- 数组操作 :数据的增删改查(
push/filter/map) - DOM 操作 :数据驱动视图(
render函数的核心作用) - 事件交互:用户操作→数据变化→视图更新的闭环
- 事件流 :
stopPropagation()解决嵌套元素冲突 - 日期对象:时间格式化与展示
- 本地存储 :
localStorage实现数据持久化 - 正则表达式:表单输入合法性验证
这些技能是前端开发的 "基础设施",无论是开发 ToDo、电商、管理系统,都离不开这套核心逻辑。建议结合今天的案例,尝试扩展功能(如待办分类、优先级设置),在实践中深化理解。