主题
黑马就业数据平台(案例实战)(一)
本页对应 黑马就业数据平台(案例实战),共 8 段视频,约 52 分钟。
学习目标
- 能将 ECharts 社区地图示例整合到数据看板页面,正确引入
china.js并调用渲染函数,使籍贯分布地图正常显示。 - 能遍历本地省份基准数据,使用
includes、find等方法与后端返回的省份数据匹配,并将匹配结果回填到dataList的value中,验证地图颜色和提示数据正确。 - 能调整地图配置项中的
tooltip、visualMap、geo/map、series.map、series.data等设置,使籍贯分布图的数据范围、颜色和提示信息符合需求。 - 能使用 Git 查看本地状态、提交数据看板功能代码并推送到远程仓库,验证远端仓库代码已更新。
- 能在学生端页面引入并调用公共逻辑,完成 Token 登录校验、用户名回显和退出登录,并验证未登录跳转、登录后显示用户名、退出后清除登录状态。
- 能说明公共逻辑封装到
common.js的作用,并在新页面中复用登录校验、用户名渲染和退出登录功能。
知识点
一、需求:为什么籍贯分布要用地图
看板前几项(概览、薪资走势、薪资分布、每组薪资、男女薪资分布)都已完成,只剩最后一块:籍贯分布。它要展示的是"学员都来自哪些省份、每个省有多少人",这类"地域 + 数值"的数据,用饼图或柱状图都不直观,最合适的是中国地图热力图:省份按人数上色,颜色越深人越多,鼠标移上去还能看到具体人数。

所以本节的目标很明确:在首页再渲染一个中国地图,数据源用后端 /dashboard 接口返回的 provinceData。
二、第一步:去 ECharts 社区找"半成品"
为什么需要:前几个图表都是在 ECharts 官方示例里找相似案例改的,但官方示例都偏基础,中国地图这种带视觉映射、高亮、缩放的效果,官方示例里没有现成的。
怎么想:ECharts 有一个社区(makeapie),里面是开发者按自己需求写好并上传的完整案例,复杂图形先去社区找,找到再改,比自己从零写快得多。
怎么做:打开社区页面 https://www.makeapie.cn/echarts ,切到"地图"分类,挑一个接近的案例,笔记里给出的模板地址是 https://www.makeapie.cn/echarts_content/xr1W9m5LOG.html 。
易错点:社区代码是别人按自己的需求写的,颜色可能很鲜艳、色条是横向的、数据是随机生成的定时刷新——这些都不能直接用。所以笔记里已经准备好一份"移除了随机数据和多余设置"的基础模板,直接复制这一份,不要复制社区原版:
javascript
function renderProvince(provinceData){
const dom = document.querySelector('#map')
const myEchart = echarts.init(dom)
const dataList = [
{ name: '南海诸岛', value: 0 },
{ name: '北京', value: 0 },
{ name: '天津', value: 0 },
{ name: '上海', value: 0 },
{ name: '重庆', value: 0 },
{ name: '河北', value: 0 },
{ name: '河南', value: 0 },
{ name: '云南', value: 0 },
{ name: '辽宁', value: 0 },
{ name: '黑龙江', value: 0 },
{ name: '湖南', value: 0 },
{ name: '安徽', value: 0 },
{ name: '山东', value: 0 },
{ name: '新疆', value: 0 },
{ name: '江苏', value: 0 },
{ name: '浙江', value: 0 },
{ name: '江西', value: 0 },
{ name: '湖北', value: 0 },
{ name: '广西', value: 0 },
{ name: '甘肃', value: 0 },
{ name: '山西', value: 0 },
{ name: '内蒙古', value: 0 },
{ name: '陕西', value: 0 },
{ name: '吉林', value: 0 },
{ name: '福建', value: 0 },
{ name: '贵州', value: 0 },
{ name: '广东', value: 0 },
{ name: '青海', value: 0 },
{ name: '西藏', value: 0 },
{ name: '四川', value: 0 },
{ name: '宁夏', value: 0 },
{ name: '海南', value: 0 },
{ name: '台湾', value: 0 },
{ name: '香港', value: 0 },
{ name: '澳门', value: 0 },
]
const option = {
title: {
text: '籍贯分布',
top: 10,
left: 10,
textStyle: {
fontSize: 16,
},
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c} 位学员',
borderColor: 'transparent',
backgroundColor: 'rgba(0,0,0,0.5)',
textStyle: {
color: '#fff',
},
},
visualMap: {
min: 0,
max: 6,
left: 'left',
bottom: '20',
text: ['6', '0'],
inRange: {
color: ['#ffffff', '#0075F0'],
},
show: true,
left: 40,
},
geo: {
map: 'china',
roam: false,
zoom: 1.0,
label: {
normal: {
show: true,
fontSize: '10',
color: 'rgba(0,0,0,0.7)',
},
},
itemStyle: {
normal: {
borderColor: 'rgba(0, 0, 0, 0.2)',
color: '#e0ffff',
},
emphasis: {
areaColor: '#34D39A',
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
},
series: [
{
name: '籍贯分布',
type: 'map',
geoIndex: 0,
data: dataList,
},
],
}
myEchart.setOption(option)
}三、第二步:整合到项目(别忘了 china.js)
为什么需要:地图和折线图、饼图不一样,它的省份轮廓来自一个独立的 JS 文件。项目里原来只引入了 echarts.js,如果不额外引入 china.js,echarts.init 不报错,但地图区域一片空白。
怎么做:在页面里引入中国地图的 JS,然后在 index.js 中声明 renderProvince,并在 getData 里解构出 provinceData 后调用它。
易错点:函数声明了但没调用,页面不会有任何变化——这是本节最容易卡住的地方,一定要回到 getData 里补上调用。
javascript
// 渲染籍贯分布
function renderProvince(provinceData) {
const dom = document.querySelector('#map')
const myEchart = echarts.init(dom)
const dataList = [
{ name: '南海诸岛', value: 0 },
{ name: '北京', value: 0 },
{ name: '天津', value: 0 },
{ name: '上海', value: 0 },
{ name: '重庆', value: 0 },
{ name: '河北', value: 0 },
{ name: '河南', value: 0 },
{ name: '云南', value: 0 },
{ name: '辽宁', value: 0 },
{ name: '黑龙江', value: 0 },
{ name: '湖南', value: 0 },
{ name: '安徽', value: 0 },
{ name: '山东', value: 0 },
{ name: '新疆', value: 0 },
{ name: '江苏', value: 0 },
{ name: '浙江', value: 0 },
{ name: '江西', value: 0 },
{ name: '湖北', value: 0 },
{ name: '广西', value: 0 },
{ name: '甘肃', value: 0 },
{ name: '山西', value: 0 },
{ name: '内蒙古', value: 0 },
{ name: '陕西', value: 0 },
{ name: '吉林', value: 0 },
{ name: '福建', value: 0 },
{ name: '贵州', value: 0 },
{ name: '广东', value: 0 },
{ name: '青海', value: 0 },
{ name: '西藏', value: 0 },
{ name: '四川', value: 0 },
{ name: '宁夏', value: 0 },
{ name: '海南', value: 0 },
{ name: '台湾', value: 0 },
{ name: '香港', value: 0 },
{ name: '澳门', value: 0 },
]
// 筛选数据
dataList.forEach(item => {
const res = provinceData.find(v => {
return v.name.includes(item.name)
})
// 数据赋值
if (res !== undefined) {
item.value = res.value
}
})
const option = {
title: {
text: '籍贯分布',
top: 10,
left: 10,
textStyle: { fontSize: 16 },
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c} 位学员',
borderColor: 'transparent',
backgroundColor: 'rgba(0,0,0,0.5)',
textStyle: { color: '#fff' },
},
visualMap: {
min: 0,
max: 6,
bottom: '20',
text: ['6', '0'],
inRange: { color: ['#ffffff', '#0075F0'] },
show: true,
left: 40,
},
geo: {
map: 'china',
roam: false,
zoom: 1.0,
label: {
normal: { show: true, fontSize: '10', color: 'rgba(0,0,0,0.7)' },
},
itemStyle: {
normal: { borderColor: 'rgba(0, 0, 0, 0.2)', color: '#e0ffff' },
emphasis: {
areaColor: '#34D39A',
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
},
series: [
{ name: '籍贯分布', type: 'map', geoIndex: 0, data: dataList },
],
}
myEchart.setOption(option)
}
// 首页-统计数据
async function getData() {
const res = await axios({ url: '/dashboard' })
const { overview, year, salaryData, groupData, provinceData } = res.data
renderOverview(overview)
renderYearSalary(year)
renderSalary(salaryData)
renderGroupSalary(groupData)
renderGenderSalary(salaryData)
// 调用函数-渲染籍贯分布
renderProvince(provinceData)
}四、读懂 option:每个配置项在管什么
为什么需要:从社区拿来的代码能跑,但不知道哪一行管什么,就没法改。建议对照页面一项一项试。
怎么做(对照上图理解):

title:左上角"籍贯分布"四个字;tooltip:鼠标悬停提示,formatter: '{b}: {c} 位学员'里{b}是省份名、{c}是数值;visualMap:左下角色条,min/max是数值范围,text: ['6','0']是色条两端文字,inRange.color是"白色 → 蓝色"的渐变,left: 40是距左边 40px;geo:地图本体,map: 'china'指定中国地图,roam控制能否缩放拖拽,zoom是缩放比,label是省份文字,itemStyle.normal是默认底色和边框,emphasis.areaColor是鼠标移上去的高亮色(绿色);series:type: 'map'表示地图系列,geoIndex: 0对应上面的geo,data就是我们传进去的dataList。
易错点:max 和 text 是两处独立配置,只改 max 不改 text,色条上仍显示"6",两者必须一起改。
五、第三步:调整数据——为什么不能直接替换
为什么需要:dataList 里有 35 个省份(含港澳台、南海诸岛),是"全国底图数据",值全是 0;而 provinceData 只有 27 条,且只包含有数据的省份,名字还带"省/自治区"。直接把 provinceData 赋给 data,没数据的省份会显示成 NA,颜色也乱了。
怎么想:以本地 35 条为主循环,拿每一条的 name 去服务器数组里找对应项,找到就把它的 value 赋给本地这一条,找不到就保持 0。
怎么做:用 forEach 遍历 dataList,用 find 在 provinceData 中找匹配项,判断 res !== undefined 后赋值(见上面"筛选数据"那一段)。
易错点:
- 不能用
===全等比较,本地是"河北"、服务器是"河北省",必须用includes:v.name.includes(item.name)("河北省".includes("河北") 为 true); find找不到返回undefined,直接res.value会报错,必须先判断;- 循环方向别反,要拿 35 条去 27 条里找。
六、收尾:提交与小练习
功能完成后提交代码,index.js 已被 Git 管理,可以用合并写法:
bash
git commit -am "数据看板-籍贯分布"
git push留一个小练习:visualMap 的 max 和 text 现在写死成 6,但实际最多可能是 10。可以从 dataList 中取出 value 的最大值,动态设置给 max 和 text 两项。
代码上传的目标:让远端仓库成为最新版本

为什么需要: 数据看板首页已经写完,本地代码只存在自己电脑上并不安全,也不方便换电脑继续做。把代码上传到 Gitee 后,远端仓库就有了最新版本,后续拉取、推送和协作才有基础。
怎么想: 代码上传不是“只执行一次 push”就结束。更稳妥的思路是:先确认本地状态,再拉取远端最新代码,保证本地和远端进度一致;然后把本地改动提交到本地仓库;最后推送到远端。笔记里把核心步骤概括为“拉取(确保进度一致)”和“推送”,这是主线,但推送前还要有“提交”这一环。
怎么做: 按“查看状态 → 拉取 → 提交 → 推送”的顺序做。转写稿里早上先查看本地状态,发现没有待提交内容,再执行 git pull,确认远端也没有更新后才开始当天任务。这个习惯能避免很多推送失败。
易错点: 不要一上来就 git push,先确认本地和远端是否同步;不要把“工作区有改动”误认为“已经提交”;转写稿中提到的“get”是口误/同音,正确命令是 git。
上传前先检查状态并拉取
为什么需要: 如果远端已经有别人或自己之前提交的新代码,而本地没有拉取,直接推送可能被拒绝,甚至产生冲突。先拉取是为了让本地基于最新版本继续工作。
怎么想: 每次开始干活前先看本地状态,再拉远端。转写稿中明确说:先看本地状态,发现是“nothing to commit”,没有任何提交,然后再 git pull 拉取远端,发现远端也没有更新,这时才可以开始今日任务。
怎么做: 可以先执行:
bash
git status
git pullgit status 用来确认当前有没有未提交的改动;git pull 用来拉取远端最新代码。如果本地有未提交改动,要先判断是提交、暂存还是处理冲突,不要直接覆盖。
易错点: 本地有改动时直接 pull 可能产生冲突;拉取后不看命令输出,误以为已经同步;把“本地没提交”和“远端没更新”混为一谈。
提交本地改动:add + commit 与 commit -a
为什么需要: Git 推送的是“提交记录”,不是工作区里刚改完的文件。数据看板写完后,必须先把改动提交到本地仓库,push 才有内容可推。
怎么想: 转写稿里提到,以前常用 git add . 再 git commit,但这次 index.js 已经被 Git 管理过、也提交过,所以可以使用 git commit -a 合并“提交已跟踪文件”的动作。注意:新文件还没被 Git 跟踪时,-a 不会自动包含它。
怎么做: 常规写法:
bash
git add .
git commit -m "首页数据看板功能完成"如果确认改动都发生在已跟踪文件里,也可以:
bash
git commit -a -m "首页数据看板功能完成"提交信息要写清楚,转写稿中用的就是“首页数据看板功能完成”。
易错点: git commit -a 不能替代所有场景,新增文件仍要先 git add;提交信息不要只写“修改”“更新”这类无法判断内容的词;提交前用 git status 再确认一次文件列表。
推送到 Gitee 并确认结果
为什么需要: 本地提交只保存在本机,推送到 Gitee 后远端仓库才会更新,换电脑或后续拉取才能拿到这份代码。
怎么想: 笔记里的核心步骤是拉取和推送:
bash
git pull
git push转写稿里最后上传时没有再次执行 pull,原因是早上已经拉取过,远端没有新变化,所以直接执行了推送。这个细节要理解成“刚同步过才可以省掉”,不是永远不拉取。
怎么做: 提交完成后执行 git push,看命令输出是否成功;再到 Gitee 远端仓库确认最新提交是否存在。以后换到任何一台电脑,仍然是先拉取、再推送。
易错点: 把 push 当成自动提交,忘记先 commit;多人协作时长期不 pull 就直接 push;看到本地提交成功就以为远端也成功了,实际要以 push 结果和远端仓库为准。
本节目标:把公共逻辑复用到学生端
为什么需要: 首页已经做过登录校验、渲染用户名、退出登录,并且这些逻辑已经抽到 common.js 中。学生端页面同样需要这些能力:不能让人不登录就直接访问学生信息页,页面要显示当前登录用户,也要能退出登录。如果每个页面都重写一遍,维护成本高,还容易出现行为不一致。
怎么想: 这次不是重新设计功能,而是“整合调用”。先确认 common.js 里已经有对应函数,再在学生端自己的 student.js 中按页面初始化顺序调用它们。转写稿里提到的 check token、render your name、logout,与笔记中的 checkLogin()、renderUsername()、registerLogout() 是同一类公共逻辑,实际以项目中的函数名为准。
怎么做: 在 student.js 中整合以下调用:
javascript
// 整合函数-登录校验
checkLogin()
// 整合函数-渲染用户名
renderUsername()
// 整合函数-退出登录逻辑
registerLogout()易错点: 不要只把函数定义复制过来却不调用;要确认 common.js 已经在学生端页面中引入,并且先于 student.js 加载;函数名要和 common.js 中保持一致;登录校验应尽早执行,避免页面先展示内容再跳转。
登录校验:先拦住未登录访问
为什么需要: 学生端展示的是学生期望薪资、就业薪资等信息,不适合未登录用户直接查看。转写稿中有一个很典型的调试过程:把登录信息删掉后刷新,页面仍然停留在学生端,这说明页面缺少登录校验。
怎么想: 登录校验的目标不是“登录后做什么”,而是“没有登录时不能继续访问”。既然 common.js 中已有公共校验函数,学生端只需要在页面初始化时调用,不需要重新写一套判断。
怎么做: 在 student.js 中调用 checkLogin()。整合后回到浏览器验证:直接访问学生端页面时,应出现“请先登录”之类的提示并跳转,而不是继续展示学生数据。
易错点: 校验函数调用太晚,页面内容已经渲染;common.js 路径写错导致函数不存在;只复制函数但没有执行;校验失败后的跳转逻辑被其他代码覆盖。
渲染用户名:让页面显示当前登录人
为什么需要: 学生端也是登录后的业务页面,页面通常需要显示当前登录用户。如果每个页面都自己从本地存储里取用户名、再操作 DOM,就会重复且容易漏改。
怎么想: 渲染用户名属于公共展示逻辑,已经在 common.js 中封装。学生端只需要调用 renderUsername(),让公共函数去完成取值和显示。
怎么做: 在 student.js 中调用 renderUsername()。转写稿中的验证方式是:登录后进入学生端,观察页面用户名是否成功回显;回显成功说明公共函数已经生效。
易错点: 在登录状态尚未准备好时调用;页面中承载用户名的元素不存在或选择器不一致;函数名拼写错误;重复调用导致重复绑定或重复渲染。
退出登录:把退出动作接到学生端
为什么需要: 学生端也需要退出登录入口。退出逻辑如果只写在首页,学生端就无法复用,用户体验和代码维护都不好。
怎么想: 退出登录通常包含“找到退出按钮并绑定事件”以及“清除登录信息并跳转”。笔记中把它整合为 registerLogout(),说明学生端只需要注册/调用公共退出逻辑。
怎么做: 在 student.js 中调用 registerLogout()。整合后点击学生端退出按钮,验证是否能清除登录状态并回到登录页。
易错点: 退出按钮还没加载就绑定事件;重复调用导致同一按钮绑定多次;退出后没有清理 token;退出后页面仍可通过后退继续看到内容,需要配合登录校验一起验证。
整合后的验证与提交
为什么需要: 公共逻辑整合完成后必须做页面级验证,否则“代码写了”不等于“功能生效”。转写稿的验证顺序很清楚:先验证未登录不能进学生端,再登录验证用户名回显,最后点击退出验证退出功能。
怎么想: 三个功能都来自 common.js,学生端只负责调用。验证时按“未登录访问 → 登录后进入 → 退出登录”的路径走一遍,能覆盖主要交互。
怎么做: 保存代码后在浏览器中逐项检查;确认无误后提交 Git:
bash
git add .
git commit -m"信息管理-公共逻辑整合"易错点: 只测登录后效果,不测未登录拦截;只测首页不测学生端;提交前没有检查 common.js 是否被正确引入;提交信息与本次改动不一致。
课件图示








代码示例
1. 数据看板 · 籍贯分布(完整可运行 HTML)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>数据看板 · 籍贯分布</title>
<style>
body { margin: 0; }
/* 地图容器必须有宽高,否则 echarts.init 拿不到尺寸,图表不显示 */
#map { width: 600px; height: 480px; }
</style>
</head>
<body>
<div id="map"></div>
<!-- 1. echarts 核心库 -->
<script src="./lib/echarts.min.js"></script>
<!-- 2. 中国地图矢量数据(echarts 官网「第三方脚本」里下载的 china.js)
少了它,geo.map = 'china' 会直接报错、地图出不来 -->
<script src="./lib/china.js"></script>
<script>
// ===== 模拟后端 /dashboard 接口返回的 provinceData(局部数据,value 不为 0)=====
const provinceData = [
{ name: '北京', value: 10 },
{ name: '河北省', value: 2 },
{ name: '新疆维吾尔自治区', value: 2 },
{ name: '内蒙古自治区', value: 1 },
{ name: '江苏省', value: 2 }
]
// 渲染籍贯分布
function renderProvince(provinceData) {
const dom = document.querySelector('#map')
const myEchart = echarts.init(dom)
// 本地基准数据:全国 35 个省份,value 全部为 0
const dataList = [
{ name: '南海诸岛', value: 0 },
{ name: '北京', value: 0 },
{ name: '天津', value: 0 },
{ name: '上海', value: 0 },
{ name: '重庆', value: 0 },
{ name: '河北', value: 0 },
{ name: '河南', value: 0 },
{ name: '云南', value: 0 },
{ name: '辽宁', value: 0 },
{ name: '黑龙江', value: 0 },
{ name: '湖南', value: 0 },
{ name: '安徽', value: 0 },
{ name: '山东', value: 0 },
{ name: '新疆', value: 0 },
{ name: '江苏', value: 0 },
{ name: '浙江', value: 0 },
{ name: '江西', value: 0 },
{ name: '湖北', value: 0 },
{ name: '广西', value: 0 },
{ name: '甘肃', value: 0 },
{ name: '山西', value: 0 },
{ name: '内蒙古', value: 0 },
{ name: '陕西', value: 0 },
{ name: '吉林', value: 0 },
{ name: '福建', value: 0 },
{ name: '贵州', value: 0 },
{ name: '广东', value: 0 },
{ name: '青海', value: 0 },
{ name: '西藏', value: 0 },
{ name: '四川', value: 0 },
{ name: '宁夏', value: 0 },
{ name: '海南', value: 0 },
{ name: '台湾', value: 0 },
{ name: '香港', value: 0 },
{ name: '澳门', value: 0 }
]
// 筛选数据:拿本地的 35 个省份,去服务器返回的局部数据里检索
dataList.forEach(item => {
const res = provinceData.find(v => {
return v.name.includes(item.name)
})
// 数据赋值:找到了才赋,没找到保持 0
if (res !== undefined) {
item.value = res.value
}
})
const option = {
title: {
text: '籍贯分布',
top: 10,
left: 10,
textStyle: { fontSize: 16 }
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c} 位学员',
borderColor: 'transparent',
backgroundColor: 'rgba(0,0,0,0.5)',
textStyle: { color: '#fff' }
},
visualMap: {
min: 0,
max: 6,
left: 40,
bottom: '20',
text: ['6', '0'],
inRange: {
color: ['#ffffff', '#0075F0']
},
show: true
},
geo: {
map: 'china',
roam: false,
zoom: 1.0,
label: {
normal: {
show: true,
fontSize: '10',
color: 'rgba(0,0,0,0.7)'
}
},
itemStyle: {
normal: {
borderColor: 'rgba(0, 0, 0, 0.2)',
color: '#e0ffff'
},
emphasis: {
areaColor: '#34D39A',
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
},
series: [
{
name: '籍贯分布',
type: 'map',
geoIndex: 0,
data: dataList
}
]
}
myEchart.setOption(option)
}
renderProvince(provinceData)
</script>
</body>
</html>关键行与易错点
china.js必须引在echarts.min.js之后、业务脚本之前;它负责注册china这个地图名。少了它geo.map: 'china'会报 “Map china not exists”,地图一片空白。#map容器必须写死宽高。echarts.init(dom)是按容器实际尺寸计算的,父级没高度就会渲染成 0×0。dataList是本地基准数据(35 个省份,全 0),不能直接用后端返回的 27 条去替换series.data——那样没数据的省份会从地图上消失。- 匹配用
v.name.includes(item.name)而不是===:后端返回的是「河北省 / 新疆维吾尔自治区」,本地是「河北 / 新疆」,全等永远匹配不上,会全部渲染成 “NaN 位学员”。 find找不到返回undefined,所以必须先判断res !== undefined再赋值,否则会写出value: undefined,地图上该省份直接变色异常。visualMap的min/max和text: ['6','0']是写死的,真实数据最大值变化后要同步改这两个地方,否则颜色分档对不上。
2. 信息管理页 · 公共逻辑整合(student.js)
html
<!-- student.html 底部:顺序不能乱 -->
<script src="./lib/axios.min.js"></script>
<script src="./js/common.js"></script> <!-- 公共逻辑:checkLogin / renderUsername / registerLogout -->
<script src="./js/student.js"></script> <!-- 当前页面自己的逻辑 -->javascript
// js/student.js
// 整合函数 - 登录校验(没有 token 就提示并跳回登录页)
checkLogin()
// 整合函数 - 渲染用户名(把登录时存的名字回显到顶部)
renderUsername()
// 整合函数 - 退出登录逻辑(内部完成按钮事件绑定)
registerLogout()
// 后续再写本页自己的增删改查逻辑……关键行与易错点
- 三个函数都定义在
common.js里(上一节已封装好),student.js只负责调用,不要再复制一遍实现——否则以后要改登录逻辑就得改 N 个页面。 common.js的<script>必须放在student.js之前,否则调用时会报checkLogin is not defined。- 调用顺序上
checkLogin()放最前面:未登录直接跳走,后面的渲染和事件绑定就没必要执行了。 - 退出登录叫
registerLogout()而不是logout(),因为它内部做的是“注册点击事件”,页面加载时调用一次即可,不要放进点击回调里反复绑定。 - 整合完成后自测:清掉 localStorage 里的 token 再刷新学生端,应该被拦回登录页;正常登录后进入学生端,用户名能回显、点退出能退出——三个都通过才算整合成功。
常见错误
现象:页面留白,地图区域什么都不渲染,控制台提示地图不存在(
Map china not exists)。 原因:只引入了echarts.min.js,没有引入并注册china.js地图数据文件。 修法:确认china.js的<script>在 echarts 之后加载,Network 面板确认请求 200;换世界地图同理,要换成对应的地图 JS。现象:地图能画出来,但只有零星几个省份有颜色,其余省份 tooltip 显示
NaN 位学员或空白。 原因:把后端返回的provinceData直接赋给series.data。后端只返回 value 不为 0 的部分数据(如 27 条),而地图需要全部 35 项骨架。 修法:保留本地全量dataList,遍历它去provinceData里检索,命中才回填 value,最后仍把dataList交给 series。现象:明明有数据的省份(如河北 10 人)地图上仍是白色,没有任何颜色。 原因:用全等比较名称,
'河北省'与'河北'永远不相等,find全部返回undefined。 修法:改用includes做包含匹配,注意方向是「后端长名.includes(本地短名)」,必要时双向判断。现象:控制台报
Cannot read properties of undefined (reading 'value'),图表渲染中断。 原因:find没找到时返回undefined,代码未判空就直接取.value。 修法:赋值前加if (res !== undefined)(或if (res))守卫;找不到就保持原值 0。现象:颜色深浅区分不出来,10 人的省份和 6 人的省份颜色一样,图例最大值只显示到 6。 原因:
visualMap的max和text写死为 6,与实际数据最大值(如 10)不一致。 修法:遍历dataList求最大 value,动态设置max与text: [String(max), '0'],并对 max 为 0 的边界情况单独处理。现象:改了代码刷新页面图表没变化,或控制台警告
There is a chart instance already initialized on the dom;也有时图表尺寸为 0。 原因:同一 DOM 被重复echarts.init;或容器在隐藏/无宽高状态下初始化。 修法:初始化前用echarts.getInstanceByDom(dom)复用已有实例或先dispose;确保容器有明确宽高,并在容器尺寸变化时resize。现象:
git commit -am "xxx"之后发现新文件没提交上去;或git push被 rejected。 原因:-am只对已被 Git 跟踪的文件生效,新增文件必须git add;push 被拒是远端有新提交。 修法:新文件先git add .;push 前先git pull,保持本地与远端进度一致。现象:
student.js里已经把三个公共函数复制过去了,但页面不登录仍能直接访问,用户名也不显示。 原因:只复制了函数定义,没有在页面入口处调用;或调用顺序写在数据请求之后,校验形同虚设。 修法:在student.js顶部依次调用checkLogin()、renderUsername()、registerLogout(),且checkLogin()必须早于任何数据请求。
练习
动态刻度:把
visualMap的min/max/text改为根据dataList计算得出。要求:数据全为 0 时图表不报错、不出现max: 0的异常刻度,并在页面上验证至少两个不同数据量级的渲染效果。封装匹配函数:写出
mergeProvinceData(dataList, provinceData),返回合并后的新数组(不修改入参),要求用Map把匹配复杂度从 O(n·m) 降到 O(n+m),并兼容「河北省 / 河北」「内蒙古自治区 / 内蒙古」「新疆维吾尔自治区 / 新疆」这类命名粒度差异。排查题:某同学这样写 ——
series[0].data = provinceData,且visualMap.max写死为 6。请列出至少两个可观察到的现象,逐个说明原因并给出最小改动方案。公共逻辑迁移:在
student.js中整合checkLogin/renderUsername/registerLogout。写清调用顺序,并回答:如果把checkLogin()写在axios请求之后,会出现什么后果?为什么这三个函数应该放在common.js而不是各自页面里?Git 实操:本次改动包括「修改
index.js」和「新增student.js」。请写出从查看状态到推送完成的完整命令序列,并说明哪一步不能省、为什么git commit -am在这个场景下不够用。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 1反馈 | 06:02 |
| 2 | 2复习 | 08:58 |
| 3 | 3今日内容介绍 | 01:25 |
| 4 | day04-Git&黑马就业数据平台-01案例-籍贯分布代码整合 | 09:25 |
| 5 | 案例-调整数据 | 10:57 |
| 6 | 案例-调整数据2 | 09:11 |
| 7 | 案例-数据看板页面功能完成 | 02:35 |
| 8 | 案例-公共代码调用 | 04:03 |
小结
- 复杂图表(地图、关系图、3D 等)优先去社区找现成模板,但拿回来第一件事是做减法:删随机数据、删多余配色、删用不上的交互,再谈接入。
- 地图类图表真正的难点不是配置项,而是数据形状:地图要全量省份骨架,后端只给局部数据,两者必须靠回填而非直接替换来对齐。
- 名称匹配一律用包含而不是全等,因为地图数据与业务数据的命名粒度天然不一致;匹配方向搞反同样会全部落空。
visualMap的max与text是「数据表达」的一部分,写死就等于谎报数据;刻度必须由实际数据推导。- ECharts 的 init → option → setOption 三步没变,地图只是多了一个「地图 JS 依赖」;出问题时先查依赖加载,再查配置。
- 公共逻辑抽到
common.js的价值在于多页面复用,抽了不调用等于没抽,且校验类调用必须排在业务请求之前。 - 提交节奏:一个功能完成就 commit 一次;push 前先 pull;
-am管不了未跟踪文件,新增文件必须add。 - 配置项记不住是正常的,能按关键字(
tooltip/visualMap/geo/series)在配置项手册里检索到,才是可持续的能力。