Web APIs 入门到实战(day5):解决数据丢失痛点——JS 本地存储 + BOM 操作实战案例(实现数据持久化学生就业表)
在 JavaScript 学习中,Web APIs 是连接语法与实际开发的关键桥梁。第 5 天的学习聚焦 BOM 操作与本地存储核心技能,不仅能让我们灵活操控浏览器窗口,还能实现数据持久化存储,最终独立完成学生就业表的开发。本文将从基础概念到实战案例,系统梳理知识点,助力快速掌握核心技能。
一、JavaScript 的组成与执行机制
要学好 BOM 操作,首先得明确它在 JS 体系中的位置,以及 JS 的执行逻辑,这是后续开发的基础。
1. JS 的三大核心组成
JavaScript 之所以能实现交互功能,核心由三部分构成:
- ECMAScript:JS 的语法核心,定义了变量、循环、对象等基础语法规则。
- DOM:文档对象模型,提供操作 HTML 文档元素的 API,比如修改节点内容、样式等。
- BOM:浏览器对象模型,提供操作浏览器窗口的 API,比如控制地址栏、定时器等。
2. JS 单线程执行机制
JS 是单线程语言,同一时间只能执行一个任务,这就导致了任务需要排队执行。为了解决 “长时间任务阻塞页面” 的问题,JS 将任务分为两类:
- 同步任务:在主线程执行栈中顺序执行,前一个任务完成后才执行下一个。
- 异步任务:不阻塞主线程,先提交到 Web API 进程处理,完成后进入任务队列等待,主线程空闲时再执行。
- 常见类型:点击 /resize 等普通事件、load/error 等资源加载事件、setTimeout/setInterval 定时器。
- 执行流程:先执行执行栈中的同步任务 → 异步任务完成后推入任务队列 → 同步任务执行完毕,按顺序读取任务队列中的异步任务,推入执行栈执行(循环往复)。
二、BOM 核心操作:掌控浏览器窗口
BOM(Browser Object Model)即浏览器对象模型,核心是window全局对象,所有 BOM 属性和方法都挂载在window上,调用时可省略window前缀。
1. window 对象:JS 的顶级对象
window是全局对象,所有全局变量、函数都会自动成为其属性和方法。- 常见的
document、alert()、console.log()等,本质都是window的属性。
2. 定时器:控制代码执行时机
定时器是 BOM 中最常用的功能,分为延迟执行和间歇执行两类:
- 延迟函数 setTimeout:延迟指定时间后执行一次回调函数。
- 语法:
const timerId = setTimeout(回调函数, 延迟毫秒数) - 核心特点:返回正整数定时器编号,仅执行一次;延迟期间后续代码正常执行。
- 清除方法:
clearTimeout(timerId)(通过编号取消定时器)。
- 语法:
- 间歇函数 setInterval:每隔指定时间重复执行回调函数(本文重点聚焦延迟函数,间歇函数用法类似)。
// 示例:3秒后执行一次回调,随后取消(实际开发可根据需求调整)
let timerId = setTimeout(() => {console.log('延迟3秒执行,仅执行一次');
}, 3000);
// 如需取消,调用clearTimeout(timerId)
3. location 对象:操控浏览器地址栏
location对象存储了 URL 的完整信息,可实现地址跳转、参数获取等功能,核心属性和方法如下:
| 属性 / 方法 | 说明 |
|---|---|
| href | 获取完整 URL,赋值可实现页面跳转(如location.href = "https://www.baidu.com") |
| search | 获取 URL 中?后的参数(如?username=zhangsan&age=20) |
| hash | 获取 URL 中#后的哈希值(常用于单页应用路由,如#user) |
| reload() | 刷新当前页面,传入true表示强制刷新(类似 Ctrl+F5) |
// 示例:获取参数与刷新页面
console.log(location.search); // 打印URL参数
const refreshBtn = document.querySelector('.refresh');
refreshBtn.addEventListener('click', () => {location.reload(true); // 强制刷新
});
4. navigator 对象:识别浏览器环境
navigator对象记录了浏览器的核心信息,常用userAgent属性检测设备类型,实现 PC / 移动端页面适配:
// 示例:检测设备并跳转对应站点
(function () {const userAgent = navigator.userAgent;const isMobile = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/) || userAgent.match(/(iPhone\sOS)\s([\d_]+)/);if (isMobile) {location.href = 'http://m.itcast.cn'; // 移动端跳转移动站点}
})();
5. history 对象:管理浏览器历史记录
history对象对应浏览器地址栏的前进、后退操作,常用方法:
back():后退一页(等价于history.go(-1))。forward():前进一页(等价于history.go(1))。- 适用场景:OA 系统、后台管理系统等需要历史记录导航的场景。
三、本地存储:实现数据持久化的核心方案
本地存储能将数据保存在浏览器中,即使页面刷新或关闭,数据也不会丢失,是实现 “页面刷新数据不丢” 的关键技术,容量约 5M,满足大部分前端存储需求。
1. 两种本地存储方案对比
| 特性 | localStorage(重点) | sessionStorage(了解) |
|---|---|---|
| 存储周期 | 永久存储,除非手动删除 | 会话级存储,关闭浏览器窗口后清除 |
| 共享范围 | 同一浏览器同源页面共享 | 仅当前窗口 / 标签页共享 |
| 核心用法 | 存储长期有效数据(如用户偏好、就业表数据) | 存储临时数据(如表单临时输入) |
2. localStorage 基础用法
localStorage以键值对形式存储,且仅支持字符串类型数据,核心语法:
- 存储数据:
localStorage.setItem('key', 'value') - 获取数据:
localStorage.getItem('key') - 删除数据:
localStorage.removeItem('key') - 修改数据:重新调用
setItem,覆盖原有 key 的值
// 示例:存储、获取、修改用户信息
// 存储
localStorage.setItem('uname', 'pink老师');
localStorage.setItem('age', '18'); // 数字也会自动转为字符串
// 获取
console.log(localStorage.getItem('uname')); // 输出:pink老师
// 修改
localStorage.setItem('uname', 'red老师');
// 删除
// localStorage.removeItem('age');
3. 存储复杂数据类型(关键技巧)
localStorage仅支持字符串存储,若要存储对象、数组等复杂数据类型,需通过JSON进行转换:
- 存储时:用
JSON.stringify(复杂数据)将其转为 JSON 字符串。 - 获取时:用
JSON.parse(JSON字符串)将其转回原数据类型。
JSON 字符串规则:属性名和字符串类型的属性值必须用双引号包裹。
// 示例:存储对象类型数据
const student = {uname: '张三',age: 22,major: '计算机科学',isEmployed: false
};
// 存储:转为JSON字符串
localStorage.setItem('student', JSON.stringify(student));
// 获取:转回对象
const getStudent = JSON.parse(localStorage.getItem('student'));
console.log(getStudent.major); // 输出:计算机科学
四、实战必备:数组 map 与 join 方法
开发学生就业表时,需对数组数据进行遍历处理和格式转换,map和join是核心工具方法。
1. map 方法:数组映射(有返回值)
map用于遍历数组,对每个元素进行处理后返回新数组,重点在于有返回值(区别于 forEach 的无返回值)。
语法:const 新数组 = 原数组.map((item, index) => { return 处理后的值 })
// 示例1:给数组元素添加后缀
const names = ['pink', 'red', 'blue'];
const newNames = names.map(item => item + '老师');
console.log(newNames); // 输出:['pink老师', 'red老师', 'blue老师']// 示例2:数组元素数值运算
const scores = [80, 90, 75];
const addScores = scores.map(item => item + 5);
console.log(addScores); // 输出:[85, 95, 80]
2. join 方法:数组转字符串
join将数组元素拼接为字符串,可指定分隔符(默认用逗号分隔)。
语法:const 字符串 = 原数组.join('分隔符')
// 示例:数组元素用不同分隔符拼接
const arr = ['张三', '李四', '王五'];
console.log(arr.join(',')); // 输出:张三,李四,王五
console.log(arr.join('-')); // 输出:张三-李四-王五
console.log(arr.join('')); // 输出:张三李四王五
3. 补充:对象属性的动态访问
当属性名是变量时,需用对象[变量名]的方式访问属性,而非.语法:
const student = { uname: '张三' };
const attr = 'age';
student[attr] = 22; // 动态添加age属性
console.log(student); // 输出:{ uname: '张三', age: 22 }
五、综合实战:本地存储学生就业表(核心目标)
结合上述知识点,我们可以实现一个 “数据持久化” 的学生就业表,核心功能:添加学生就业信息、页面刷新数据不丢失、数据展示格式化。
1. 核心思路
- 页面结构:设计表单用于输入学生信息(姓名、专业、薪资、就业状态)。
- 数据存储:用
localStorage存储学生数组,添加新数据时先读取本地存储,再追加新数据并重新存储。 - 数据展示:用
map方法遍历学生数组,格式化生成 HTML 结构,用join拼接后渲染到页面。 - 数据持久化:页面加载时自动读取本地存储数据并渲染。
2. 关键代码实现
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>学生就业表</title><style>table { border-collapse: collapse; width: 80%; margin: 20px auto; }th, td { border: 1px solid #333; padding: 8px; text-align: center; }form { width: 80%; margin: 20px auto; display: flex; gap: 10px; }input, select, button { padding: 8px; flex: 1; }</style>
</head>
<body><form id="jobForm"><input type="text" name="uname" placeholder="姓名" required><input type="text" name="major" placeholder="专业" required><input type="number" name="salary" placeholder="薪资" required><select name="isEmployed" required><option value="true">已就业</option><option value="false">未就业</option></select><button type="submit">添加</button></form><table><thead><tr><th>姓名</th><th>专业</th><th>薪资</th><th>就业状态</th></tr></thead><tbody id="jobList"></tbody></table><script>// 1. 读取本地存储数据function getLocalData() {const data = localStorage.getItem('studentJobs');return data ? JSON.parse(data) : []; // 无数据时返回空数组}// 2. 保存数据到本地存储function saveLocalData(data) {localStorage.setItem('studentJobs', JSON.stringify(data));}// 3. 渲染数据到页面function renderData() {const data = getLocalData();const tbody = document.getElementById('jobList');// 用map格式化数据,join拼接为HTMLconst html = data.map(item => `<tr><td>${item.uname}</td><td>${item.major}</td><td>${item.salary}元</td><td>${item.isEmployed === 'true' ? '已就业' : '未就业'}</td></tr>`).join('');tbody.innerHTML = html;}// 4. 表单提交事件document.getElementById('jobForm').addEventListener('submit', (e) => {e.preventDefault(); // 阻止表单默认提交// 获取表单数据const formData = new FormData(e.target);const newStudent = {};formData.forEach((value, key) => newStudent[key] = value);// 读取原有数据,追加新数据const data = getLocalData();data.push(newStudent);// 保存并重新渲染saveLocalData(data);renderData();// 重置表单e.target.reset();});// 页面加载时渲染数据window.addEventListener('load', renderData);</script>
</body>
</html>
3. 功能说明
- 表单提交后,新数据会追加到本地存储的数组中。
- 页面刷新后,会自动读取本地存储数据并渲染表格。
- 就业状态通过三元表达式转换为中文显示,薪资添加 “元” 单位,格式更友好。
六、总结与拓展
第 5 天的学习核心是 “操控浏览器” 与 “数据持久化”:BOM 操作让我们能灵活控制浏览器窗口、地址栏、定时器等;本地存储则解决了 “数据临时存储” 的痛点,实现页面刷新数据不丢失。结合数组 map、join 方法,我们成功完成了学生就业表的实战开发。
