在前端开发中,LocalStorage 是浏览器提供的核心本地存储方案,而 CSS 布局与工程化编码则是提升开发效率和代码质量的关键。本文将结合实际案例,带大家从零实现一个可持久化的待办清单,同时拆解 CSS 继承 / 弹性布局的核心用法,以及前端函数式封装的工程化思想。
一、核心知识点预热:先搞懂这 3 个关键技术
在动手写代码前,我们先梳理案例中涉及的核心技术点,帮大家打通知识盲区:
1. LocalStorage:浏览器的「永久储物柜」
-
存储位置:浏览器本地,与服务器无关
-
存储特性:永久存储(除非手动清除或代码删除),页面刷新 / 关闭后数据不丢失
-
存储规则 :仅支持
key-value键值对,且值必须是字符串(对象 / 数组需用JSON.stringify()序列化) -
核心 API:
javascript
运行
javascript// 存数据 localStorage.setItem('key', JSON.stringify(数据)); // 取数据(需反序列化) JSON.parse(localStorage.getItem('key')); // 删数据(单个/全部) localStorage.removeItem('key'); localStorage.clear();
2. CSS 关键特性:这些细节能少写 80% 冗余代码
(1)继承性:不是所有属性都能「子承父业」
-
可继承属性 :
font-size、color、text-align等文本相关属性(子元素自动继承父元素样式) -
不可继承属性 :
background、width、height、border等布局 / 盒模型相关属性(需手动设置) -
实用技巧 :用
inherit强制继承父属性,比如让子元素高度跟随父元素:css
css.child { height: inherit; /* 继承父元素 height */ }
(2)outline 与 overflow:细节优化神器
- outline :元素轮廓,类似
border但不占据盒模型空间(适合表单聚焦样式) - overflow :控制子元素超出父元素时的表现(
hidden隐藏溢出、auto自动滚动)
(3)Flex 布局:快速实现居中与对齐
Flex 是现代布局方案,核心是「格式化上下文」,只需 3 行代码实现元素居中:
css
css
.parent {
display: flex; /* 开启 Flex 布局 */
justify-content: center; /* 主轴(水平)居中 */
align-items: center; /* 交叉轴(垂直)居中 */
}
3. 前端工程化:拒绝流程式代码,拥抱函数封装
当代码超过 10 行,就该考虑封装函数!核心优势:
- 复用性:同一逻辑多处调用,减少冗余
- 可维护性:隐藏实现细节,修改时只需改函数内部
- 可读性:函数名即功能,代码逻辑更清晰
二、实战:实现 LocalStorage 待办清单
1. 项目结构
plaintext
bash
todo-list/
├── common.css # 样式文件
└── index.html # 结构+逻辑文件
2. 样式文件:common.css
css
css
/* 基础重置:统一盒模型 */
html {
box-sizing: border-box;
min-height: 100vh; /* 占满视口高度 */
display: flex; /* 页面整体居中 */
justify-content: center;
align-items: center;
text-align: center; /* 文本居中 */
background-color: #f5f5f5;
}
*,
*::before,
*::after {
box-sizing: inherit; /* 继承盒模型 */
}
/* 容器样式 */
.wrapper {
padding: 20px;
max-width: 350px;
background-color: rgba(255, 255, 255, 0.95);
box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); /* 外发光效果 */
border-radius: 8px;
}
h2 {
margin: 0 0 20px;
font-weight: 200;
color: #333;
}
/* 待办列表样式 */
.plates {
margin: 0;
padding: 0;
text-align: left;
list-style: none;
}
.plates li {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
padding: 10px 0;
font-weight: 100;
display: flex; /* 复选框与文本同行 */
align-items: center;
}
.plates label {
flex: 1; /* 文本占满剩余空间 */
cursor: pointer; /* 鼠标悬浮变指针 */
color: #444;
}
/* 自定义复选框样式 */
.plates input {
display: none; /* 隐藏原生复选框 */
}
.plates input + label:before {
content: "⬜️";
margin-right: 10px;
font-size: 18px;
}
.plates input:checked + label:before {
content: "✅"; /* 选中时切换图标 */
}
/* 表单样式 */
.add-items {
margin-top: 20px;
display: flex;
gap: 10px; /* 输入框与按钮间距 */
}
.add-items input[type="text"] {
flex: 1;
padding: 10px;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 4px;
outline: 3px solid transparent;
transition: outline 0.3s;
}
.add-items input[type="text"]:focus {
outline: 3px solid rgba(14, 14, 211, 0.8); /* 聚焦高亮 */
}
.add-items input[type="submit"] {
padding: 10px 20px;
border: none;
border-radius: 4px;
background-color: rgba(14, 14, 211, 0.8);
color: white;
cursor: pointer;
transition: background-color 0.3s;
}
.add-items input[type="submit"]:hover {
background-color: rgba(14, 14, 211, 1);
}
3. 核心文件:index.html
html
预览
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LocalStorage 待办清单</title>
<link rel="stylesheet" href="./common.css">
</head>
<body>
<div class="wrapper">
<h2>LOCAL TAPAS</h2>
<ul class="plates">
<li>Loading Tapas...</li>
</ul>
<form class="add-items">
<input
type="text"
placeholder="输入待办事项"
required
name="item"
>
<input type="submit" value="+ 添加事项">
</form>
</div>
<script>
// 1. 获取 DOM 元素
const addItemsForm = document.querySelector('.add-items');
const itemsList = document.querySelector('.plates');
// 2. 从 LocalStorage 取数据(无则初始化空数组)
const items = JSON.parse(localStorage.getItem('todos')) || [];
/**
* 渲染待办列表
* @param {Array} plates - 待办数组
* @param {Element} platesList - 列表 DOM 元素
*/
function populateList(plates = [], platesList) {
// 数组 map 生成 DOM 字符串,join 拼接(避免逗号分隔)
platesList.innerHTML = plates.map((plate, index) => `
<li>
<input
type="checkbox"
data-index="${index}"
id="item${index}"
${plate.done ? 'checked' : ''}
/>
<label for="item${index}">${plate.text}</label>
</li>
`).join('');
}
/**
* 添加待办事项
* @param {Event} event - 表单提交事件
*/
function addItem(event) {
event.preventDefault(); // 阻止表单默认提交行为
// 获取输入框值(去空格)
const text = this.querySelector('[name=item]').value.trim();
if (!text) return; // 空值不添加
// 新增待办对象
const newItem = {
text,
done: false // 默认未完成
};
items.push(newItem);
// 存入 LocalStorage(序列化数组)
localStorage.setItem('todos', JSON.stringify(items));
// 重新渲染列表
populateList(items, itemsList);
this.reset(); // 重置表单
}
/**
* 切换待办完成状态
* @param {Event} event - 点击事件
*/
function toggleDone(event) {
const target = event.target;
// 只处理复选框的点击
if (target.tagName !== 'INPUT') return;
// 获取数据索引(从 data-index 属性)
const index = target.dataset.index;
// 切换完成状态
items[index].done = !items[index].done;
// 更新 LocalStorage
localStorage.setItem('todos', JSON.stringify(items));
// 重新渲染
populateList(items, itemsList);
}
// 3. 绑定事件监听
addItemsForm.addEventListener('submit', addItem);
itemsList.addEventListener('click', toggleDone);
// 4. 页面加载时渲染列表
populateList(items, itemsList);
</script>
</body>
</html>
三、关键技术拆解:为什么这么写?
1. LocalStorage 持久化逻辑
- 初始化 :页面加载时从
localStorage读取todos数据,若不存在则初始化为空数组 - 新增待办 :添加后立即用
JSON.stringify()序列化数组,存入localStorage - 状态切换 :修改待办完成状态后,同步更新
localStorage,确保刷新后状态不丢失
2. CSS 进阶技巧
- 盒模型继承 :通过
box-sizing: inherit让所有元素(包括伪元素)继承border-box,避免计算宽度时的麻烦 - Flex 布局妙用:页面整体居中、待办项复选框与文本对齐、表单输入框与按钮同行分布,都用 Flex 实现,简洁高效
- 自定义复选框 :隐藏原生复选框,用
:before伪元素实现自定义图标,提升视觉体验 - 聚焦状态优化:输入框聚焦时添加蓝色轮廓,提升交互反馈
3. 工程化编码思想
(1)函数式封装:拒绝流程式代码
- 把「渲染列表」「添加待办」「切换状态」拆分为 3 个独立函数,每个函数只做一件事
- 函数参数化:
populateList接收待办数组和列表 DOM 元素,增强复用性 - 避免全局变量污染:核心数据
items通过函数参数传递,而非依赖全局变量
(2)细节优化:提升用户体验
- 输入框去空格:用
trim()避免添加空待办 - 空值判断:输入为空时不添加待办
- 表单重置:添加后清空输入框,方便连续输入
- 事件委托:给列表父元素绑定点击事件,而非给每个复选框绑定,提升性能(尤其待办较多时)
四、扩展与优化方向
- 添加删除功能 :给每个待办项增加删除按钮,点击时删除对应项并更新
localStorage - 批量操作:实现「全选 / 全不选」「清空已完成」功能
- 数据持久化优化 :封装
localStorage操作工具函数,避免重复写JSON.stringify和JSON.parse - 样式升级:添加动画效果(如待办项添加 / 删除时的过渡动画)
- 响应式优化:适配移动端,优化小屏幕下的布局
五、总结
本文通过一个简单的待办清单案例,串联了 LocalStorage 本地存储、CSS 进阶特性和前端工程化编码思想。核心要点:
- LocalStorage 是前端持久化存储的基础,关键是掌握「序列化 / 反序列化」技巧
- CSS 不仅是样式,合理运用继承、Flex 布局和伪元素,能大幅提升开发效率和视觉体验
- 工程化编码的核心是「拆分与封装」,让代码更易维护、可复用
这个案例虽然简单,但包含了前端开发的核心思想,适合新手入门练习,也能帮助有经验的开发者巩固基础。动手试试扩展功能,让它变得更强大吧!