Skip to content

Git 入门与本地仓库(三) ​

本页对应 Git 入门与本地仓库,共 7 段视频,约 1 小时 14 分。

学习目标 ​

  • 能够使用 git checkout -b 快速创建并切换分支,并使用 git branch -D 强制删除未合并分支,完成分支管理操作。
  • 能够复现并解决 Git 分支冲突:识别冲突提示,在 VS Code 中选择保留当前更改/传入更改/双方更改,暂存并提交合并结果。
  • 能够初始化“黑马就业数据平台”项目:创建本地仓库、切换到 dev 分支,并说明项目目录及 common.js 与各页面独立 JS 文件的职责。
  • 能够在 common.js 中配置 axios 基地址,并通过发送请求验证基地址生效。
  • 能够抽取 showToast 公共轻提示函数,调用后正确显示指定提示内容。
  • 能够完成用户注册功能:收集并校验用户名和密码、发送注册请求、显示结果并延迟跳转登录页,最后提交代码记录。

知识点 ​

项目演示:先看四个页面与核心业务 ​

本节先做项目演示,再初始化项目。笔记里说得很清楚:4个页面,包含了管理类项目的核心业务。演示时不要只看“页面长什么样”,而要把它对应到业务:注册页完成用户注册;登录页完成登录并缓存登录信息;首页完成页面渲染、图表区域和8组人员切换;学生端完成学生数据的增删改查。转写稿中还演示了删除第八组一名学生后,总人数从80变79,第八组从10人变9人,这说明页面上的数字和列表是联动的。

项目演示的四个页面与核心业务截图

为什么需要先演示:管理类项目功能多,先看完整业务,后续写注册、登录、图表、学生端时才知道每段代码服务于哪个页面。怎么想:把四个页面当成四条业务线,而不是四个孤立HTML。怎么做:按“注册→登录→首页图表→学生端CRUD”的顺序演示。易错点:不要一上来抠样式;先确认业务动作和结果,例如注册成功提示、登录后跳转、删除后人数变化。

项目初始化与目录结构 ​

为什么需要:项目必须纳入Git管理,且主分支不直接写业务代码。转写稿明确说主分支是最基础结构,开发要在DEV分支。怎么想:先复制“基础模板”,再初始化仓库,再创建并切换到DEV分支。怎么做:

bash
git init
git checkout -b dev

目录中依赖Bootstrap,包含CSS、图片、JS;common.js放公共逻辑,首页、登录页、注册页、学生端各有独立JS。易错点:不要拿master直接开发;公共内容放common.js,页面独立逻辑放各自JS,避免后续维护混乱。

配置 axios 基地址 ​

为什么需要:以前每个请求都写完整地址,重复且难改。接口文档会给出基地址,配置后请求只写后半段。怎么想:所有页面基本都要发请求,所以基地址放公共的common.js。怎么做:用axios.defaults.baseURL配置接口文档给出的地址:

js
axios.defaults.baseURL = '接口文档给出的基地址'

配置后发一个测试请求。转写稿的调试过程是:在注册页发登录请求,打开浏览器Network,看到请求已经发出,只是用户名密码错误——这说明请求发出去了,基地址配置生效。易错点:测试代码用完要删除;配置完要提交一次,例如git add .、git commit -m "配置axios基地址"。

抽取公共提示框 showToast ​

为什么需要:注册成功、登录成功都要提示,不能每个页面重复写。怎么想:抽成公共函数,放在common.js,接收一个message。怎么做:获取页面中的提示框结构,创建Bootstrap Toast实例,调用show()显示,再把.toast-body内容改成传入的提示:

js
function showToast(message) {
  const toastEl = document.querySelector('.my-toast')
  const toast = new bootstrap.Toast(toastEl)
  toast.show()
  document.querySelector('.toast-body').innerHTML = message
}

易错点:转写稿中的“post”是口误,实际是Toast;要先让提示框显示,再替换内容;调用时传“注册成功”等具体消息。

注册业务:收集校验→发请求→显示结果→跳登录 ​

为什么需要:这是今天第一个实际业务。怎么想:分四步——收集注册数据并校验、发送请求、显示结果、成功后跳登录页。怎么做:给注册按钮绑定点击事件,用序列化插件拿到对象格式数据;做非空和长度校验。转写稿调试时:不输入用户名提示“用户名不能为空”;输入123提示“用户名不符合要求”;密码同理。校验通过后用axios.post简写发请求,并用async/await原地拿结果:

js
const res = await axios.post('/register', data)
showToast(res.data.message)
setTimeout(() => {
  location.href = './login.html'
}, 500)

易错点:跳转路径要从register.html出发写./login.html;如果立即跳转,提示框看不到,所以用setTimeout延迟约500毫秒;注册完成要git add .并提交“注册业务逻辑完成”。

项目初始化的目标与整体思路 ​

这一节要完成两件事:第一,把“黑马就业数据平台”的项目文件夹纳入 Git 管理,并把提供的模板代码作为第一次提交记录下来;第二,创建并切换到 dev 分支,为后续开发准备独立分支。

为什么需要先做初始化?因为后面写注册、登录、图表、学生端等功能时,代码会不断变化。如果没有 Git 记录,改错了很难回退,也不方便按功能提交。怎么想?先把“空项目 + 模板代码”变成一个受 Git 管理的本地仓库,再建立开发分支。怎么做?按笔记步骤:新建文件夹、git init、拷贝模板、git add . 和 git commit,最后 git checkout -b dev。易错点:不要先在模板文件夹里改代码再复制;初始化提交要发生在拷贝模板之后,保证第一次提交包含完整基础结构。

转写稿里先演示了项目最终效果:注册、登录、页面渲染、图表区域、学生端增删改查等。演示的目的是让我们知道这个基础模板后面要承载哪些业务,但本节只做“项目初始化”,不展开业务代码。

准备项目文件夹并初始化 Git 仓库 ​

为什么需要单独建项目文件夹?因为 Git 仓库应该围绕一个项目目录管理,避免把桌面或其他无关文件纳入版本控制。怎么想?先建一个语义明确的文件夹,再在这个文件夹下执行初始化命令。怎么做?新建文件夹“黑马就业数据平台”,在该文件夹下打开 Git Bash 或终端,输入:

bash
git init

执行后,文件夹中会出现隐藏的 .git 目录,说明本地仓库创建成功。易错点:命令要在项目文件夹内部执行,不要在桌面上直接执行;git init 只需执行一次,重复执行会重新初始化仓库。

拷贝基础模板并提交初始化记录 ​

为什么需要拷贝模板?因为项目不是从零写 HTML/CSS/JS,而是基于“黑马就业数据平台-基础模板”继续开发。怎么想?先把模板中的全部内容复制到项目文件夹下,让项目具备基础目录和公共文件,再用 Git 记录这一次“初始化”。怎么做?把素材“黑马就业数据平台-基础模板”内的所有内容拷贝到“黑马就业数据平台”文件夹下:

拷贝基础模板内容到项目文件夹

然后执行:

bash
git add .
git commit -m"初始化"

这里 git add . 把当前目录下所有变化加入暂存区,git commit -m"初始化" 生成第一次提交。易错点:提交前可用 git status 查看文件是否已暂存;提交信息要写清楚,不要留空;注意 -m 和提交信息之间要有空格。

转写稿中还提到项目模板的目录结构:有 CSS、图片、JS 等目录,js 中有公共的 common.js,也有首页、登录页、注册页、学生端各自独立的 JS 文件。公共逻辑放公共文件,页面逻辑放各自文件。这个认识对后续开发很重要,但本节先保证模板完整纳入 Git。

创建并切换到 dev 分支 ​

为什么需要 dev 分支?转写稿明确说主分支一般不直接用于开发,主分支保留最基础的结构,实际编写代码放到开发分支。怎么想?初始化提交已经在主分支上完成,接下来创建开发分支并立即切换过去。怎么做?使用“创建并切换”的快捷命令:

bash
git checkout -b dev

其中 -b 表示创建分支,checkout 表示切换,dev 是 develop 的简写。执行后当前分支就是 dev。易错点:不要先 git branch dev 再单独切换,直接用 git checkout -b dev 更简洁;分支名要统一,后面提交和合并都围绕 dev 进行。

初始化后的检查与常见易错点 ​

为什么需要检查?因为初始化、提交、切分支都是基础操作,一旦顺序错了,后面业务提交会混乱。怎么想?用状态和分支命令确认结果。怎么做?可执行:

bash
git status
git branch
git log --oneline

git status 看工作区是否干净;git branch 看当前分支前是否有 *,应显示在 dev;git log --oneline 确认“初始化”提交存在。易错点:如果 git branch 仍显示在 master,说明切换没成功;如果提交前发现模板没复制全,应补拷贝后重新 git add . 再提交,或按课堂要求处理,不要带着缺失文件继续开发。完成这些检查后,项目初始化才算真正完成。

先确认项目目录图 ​

项目目录结构

为什么需要:项目一开始就把目录职责定清楚,后面写注册、登录、图表、学生端时才不会把代码到处塞。转写里先演示最终效果,再回头搭“项目初始化”,目的就是先让目录结构稳定下来。

怎么想:把文件按“公共”和“页面私有”分开。项目里有 CSS、图片、JS,还有多个 HTML 页面;JS 里既有所有页面都可能用的逻辑,也有只属于某个页面的逻辑。

怎么做:先对照上图确认目录:common.js 放公共 JS 逻辑;js 目录下放各页面同名 JS 文件。转写中明确提到 4 个页面 JS:首页、登录页、注册页、学生端,分别对应各自的 HTML 页面。

易错点:不要看到“项目目录”就只记文件名,要记职责边界。公共代码进 common.js,页面私有代码进同名 JS;否则后面改一个提示框要改很多页面,容易漏改。

公共逻辑写在 common.js ​

为什么需要:转写里配置 axios 基地址时说得很直接:是不是所有页面基本都会发 Ajax?既然所有页面都要用,就应放到公共位置。提示框函数也一样,注册成功、登录成功都要提示,所以抽取成公共函数。

怎么想:判断标准不是“代码短不短”,而是“是不是多个页面都要用”。axios 基地址、showToast 这类跨页面能力,放 common.js;某个页面自己的点击事件、表单收集,不放公共文件。

怎么做:在 common.js 中配置基地址,示意如下(地址以接口文档为准):

js
// common.js:公共逻辑
axios.defaults.baseURL = '接口文档给出的基地址'

function showToast(message) {
  const toastEl = document.querySelector('.my-toast')
  const toast = new bootstrap.Toast(toastEl)
  toast.show()
  document.querySelector('.toast-body').innerHTML = message
}

转写里的调试过程是:配置完基地址后,在注册页发一次登录请求测试;打开浏览器 Network 面板,看到请求已经发出,虽然返回“用户名密码错误”,但说明请求地址拼接成功,基地址生效。测试代码随后删除,再提交“配置 axios 基地址”。

易错点:测试代码不要留在业务文件里;公共函数不要写成只服务某一个页面。转写还提醒:提示框内容一开始固定显示“提示消息”,必须把 message 替换进 .toast-body,否则调用时传参没有意义。

页面逻辑写在 js 目录下的同名 js 文件 ​

为什么需要:公共逻辑解决“大家都要用”,页面逻辑解决“这个页面自己要做什么”。注册页要收集账号密码、校验、发请求、显示结果、跳转登录页,这些只属于注册页,放 register.js 最合适。

怎么想:先找页面 HTML,再找它引入的同名 JS。转写中注册页叫 register.html,核心逻辑在 register.js;写点击事件时先获取按钮,再绑定 click。

怎么做:页面 JS 里按“收集并校验数据 → 发请求 → 显示结果 → 跳转”推进。转写中的关键调试是:注册成功后调用 showToast(res.data.message),再 location.href 跳登录页;但一开始跳得太快,提示框看不到,于是改为延迟约 500 毫秒再跳。路径也要从“使用该 JS 的 HTML 页面”出发找 login.html,不能从 JS 文件位置想当然。

易错点:转写反复强调“不要解构”“注意路径从 register.html 出发”。另外每完成一个小功能要 git add、git commit -m 记录;提交前看状态,红色在工作区,绿色在暂存区。目录职责清楚后,提交记录也会清楚:公共配置一次提交,页面业务一次提交。

先看问题:为什么需要配置基地址 ​

为什么需要:在 Ajax 阶段写请求地址时,经常要写完整的 http://.../api/...,每个接口前面都有一大段重复内容。项目里注册、登录等页面都要发请求,如果每次都写全,既啰嗦又容易写错。
怎么想:把“所有接口都相同的前缀”抽出来,只配置一次;以后发请求只写后半段相对路径。这个公共前缀就是 axios 的 baseURL。
怎么做:先看接口文档给出的基地址,再在公共 JS 中配置 axios.defaults.baseURL。转写稿里强调:所有页面基本都会发 Ajax,所以基地址应放在公共的 common.js 中,而不是某个单独页面里。
易错点:不要把完整地址和 baseURL 混着写,否则可能出现地址重复;配置要放在页面能引入到的公共文件里。

理解 baseURL 的规则 ​

文档地址:axios 中文文档。文档说明:baseURL 将自动加在 url 前面,除非 url 是一个绝对 URL。它可以通过设置一个 baseURL,便于为 axios 实例的方法传递相对 URL。

为什么需要:理解规则后,才知道配置后 url 应该写什么、不该写什么。
怎么想:如果 url 写的是 /login 这种相对地址,axios 会自动拼上基地址;如果写的是完整绝对 URL,就不会再拼。
怎么做:配置基地址后,请求里只保留接口后半段,例如 /login、/register。
易错点:不要以为配置了 baseURL 后所有地址都随便写;绝对 URL 不会自动加前缀,相对地址才符合预期。

配置 axios 基地址示意图

在 common.js 中配置基地址 ​

为什么需要:基地址是公共配置,放到 common.js 后,各页面引入公共 JS 就能共用。
怎么想:项目目录里 common.js 记录公共 JS 逻辑,基地址属于公共内容,所以写在这里。
怎么做:在 common.js 中添加:

javascript
// 设置基地址
axios.defaults.baseURL = 'https://hmajax.itheima.net'

易错点:地址要按接口文档复制准确;不要多写或漏写协议、域名;配置完成后要确认页面确实引入了 common.js。

在 register.js 中测试配置是否生效 ​

为什么需要:配置完不能只看代码,要发一次请求验证。
怎么想:按笔记在 register.js 中写测试请求,url 只写 /register,看最终请求是否发到基地址下。
怎么做:

javascript
axios({
  url: '/register',
  method: 'post',
  data: {
    username: 'itheima666',
    password: '123456'
  }
})

转写稿里的调试过程是:打开浏览器开发者工具的网络面板,刷新后看请求有没有发出去。演示时请求已经发出,即使返回“用户名或密码错误”,也说明请求地址已经按基地址发出,基地址配置生效。测试完成后,测试代码要删掉,不要留在业务文件里。
易错点:不要因为接口返回业务错误就认为基地址没配好,先看网络面板里的请求 URL;测试代码不是正式业务代码,测完要删除。

用 Git 记录这次配置 ​

为什么需要:每完成一个小功能就提交一次,方便回溯。
怎么想:这次只改了公共配置,提交信息写清楚“配置 axios 基地址”。
怎么做:

bash
git add .
git commit -m"配置axios基地址"

易错点:提交前确认测试代码已删除、只提交本次需要的修改;提交信息要能看懂,不要写无意义内容。

需求与目标 ​

后续注册、登录等页面都需要给用户反馈,例如“注册成功”“用户名不能为空”。如果每个页面都手写一遍提示框逻辑,代码会重复,修改起来也麻烦。因此本节要把轻提示抽取成公共函数,放到 common.js 中,任何页面调用:

javascript
showToast('提示信息')

就能显示提示。这个目标来自项目初始化后的第二个公共事情:第一件是配置 axios 基地址,第二件就是抽取公共提示框函数。转写稿里明确说,注册成功要提示、登录成功也要提示,既然都要提示,就抽一个公共函数,名字叫 showToast,接收一个参数,用来表示“注册成功还是失败”。

为什么抽成函数 ​

为什么需要: 轻提示是多个页面共用的交互,不属于某一个页面。
怎么想: 公共逻辑放公共文件。项目里已经有 common.js,它记录公共 JS 逻辑;提示框函数也放这里。
怎么做: 在 common.js 中定义 showToast(msg),页面引入 common.js 后直接调用。
易错点: 不要把函数写到某个页面的独立 JS 里,否则其他页面用不到;也不要在每个页面复制一份 Toast 代码。

结构准备与选择器 ​

笔记注明:所有页面都准备好了轻提示结构:

html
  <div class=" toast bg-rgba my-toast" data-bs-delay="1500">
    <div class="toast-body">提示消息</div>
  </div>

为什么需要: Bootstrap Toast 必须有一个真实的 DOM 结构才能实例化。
怎么想: 函数里先找到这个结构,再交给 Bootstrap 处理。结构上的关键类是 my-toast,内容区域是 .toast-body。
怎么做: 用 document.querySelector('.my-toast') 获取提示框 DOM,用 document.querySelector('.toast-body') 获取内容区域。
易错点: 如果页面没有 .my-toast,toastDom 就是 null,后面实例化会报错;如果类名写错,也会找不到。data-bs-delay="1500" 表示自动隐藏时间,结构要保留。

实例化并显示 Toast ​

参考步骤里的函数是:

javascript
// 抽取轻提示函数
function showToast(msg) {
  const toastDom = document.querySelector('.my-toast')
  // 实例化toast组件
  const toast = new bootstrap.Toast(toastDom)
  // 修改内容并显示
  document.querySelector('.toast-body').innerText = msg
  toast.show()
}

为什么需要: 只拿到 DOM 不会自动弹出,需要 Bootstrap 的 Toast 实例调用 show()。
怎么想: 转写稿里把用法拆成两步:先生成实例对象,再调用显示方法。实例化时把 toastDom 传进去,得到 toast 实例。
怎么做: new bootstrap.Toast(toastDom) 创建实例;设置内容后调用 toast.show()。
易错点: 页面必须引入 Bootstrap 的 JS,否则 bootstrap 未定义;Toast 首字母大写;传进去的是 DOM 元素,不是选择器字符串。

替换提示内容与调试 ​

转写稿里有一个很关键的调试过程:函数刚封装时,提示框能显示,但内容一直是“提示消息”,这说明只显示了结构里的默认文字,没有把参数写进去。于是要在显示前修改 .toast-body 的内容:

javascript
document.querySelector('.toast-body').innerText = msg

为什么需要: 同一个提示框要显示不同信息,不能写死“提示消息”。
怎么想: showToast 接收 msg,就把 msg 写到内容区域。
怎么做: 先调用 showToast('注册成功') 测试,刷新页面能看到“注册成功”;再改成 showToast('成功'),能看到“成功”,说明参数生效。
易错点: 如果仍然显示“提示消息”,检查是否漏了修改 .toast-body;按笔记使用 innerText 设置纯文本;内容设置和 toast.show() 的顺序要保证显示前已经改好。

Git 记录 ​

函数抽取并测试完成后,按笔记记录本次改动:

bash
git add .
git commit -m"抽取轻提示函数"

为什么需要: 每完成一个小功能就提交一次,方便回退和查看历史。
怎么想: 这次改动属于公共函数抽取,提交信息要写清楚。
怎么做: 先 git add . 暂存,再 git commit -m"抽取轻提示函数" 提交。
易错点: 提交信息不要写成无关内容;提交前确认 common.js 已保存,测试调用符合当前阶段需要。

易错点汇总 ​

  1. common.js 中函数名按笔记为 showToast,调用时大小写一致。
  2. 每个页面都要有 .my-toast 和 .toast-body 结构。
  3. 必须引入 Bootstrap JS,否则 new bootstrap.Toast 不可用。
  4. 不要用 alert 代替,转写稿明确说 alert 太丑,项目使用 Bootstrap Toast 组件。
  5. 显示内容要通过参数 msg 写入 .toast-body,不能一直显示默认“提示消息”。
  6. 测试通过后记得按 Git 记录提交。

注册功能的整体思路 ​

为什么需要:注册是用户进入系统的第一步,必须把账号、密码可靠地提交给后端,并让用户知道成功还是失败。
怎么想:把注册拆成“收集并校验数据 → 提交数据 → 显示结果”。课堂转写中先找到 register.html 和 register.js,确认页面已引入核心逻辑文件,再给注册按钮绑定点击事件,而不是一上来就发请求。
怎么做:先收集表单数据,做非空(不是“飞空”)和长度校验(不是“交验”),再发请求。
易错点:选择器写错、没校验就提交、把空值直接发给后端;校验失败要 return,不能继续往下执行。

axios 的别名方法 ​

为什么需要:每次都写 method: 'post' 比较啰嗦,别名方法让请求语义更直接。
怎么想:axios.post(url, data) 中第二个参数对应对象写法里的 data,不是 params。
怎么做:保留笔记中的对照代码:

javascript
// axios函数+对象写法
axios({
  url: 'url地址',
  method: 'post',
  data:{key:'value'}
})
// 等同于
// axios别名方法(简化方法)
// 参数1 url
// 参数2 对应到data属性
axios.post('url地址', { key: 'value'})

易错点:别名方法仍返回 Promise,仍要 await 和 try/catch;项目已配置基地址时,URL 写 /register 即可,不要重复拼完整域名;post 第二参不要误写成 params。

收集与校验注册数据 ​

为什么需要:后端需要的是账号和密码;前端先校验能减少无效请求。转写稿里先 console.log(data) 看收集结果,再逐步加非空和长度校验。
怎么想:用 serialize(form, { empty: true, hash: true }) 得到对象格式,empty: true 保留空值,便于判断“不能为空”;hash: true 得到键值对象。
怎么做:register.js 参考逻辑如下:

javascript
/**
 * 用户注册
 *  1. 收集并校验数据
 *  2. 数据提交
 * */
document.querySelector('#btn-register').addEventListener('click', async () => {
  // 1. 收集并校验数据
  const form = document.querySelector('.register-form')
  const data = serialize(form, { empty: true, hash: true })
  // console.log(data)
  const { username, password } = data
  console.log(username, password)
  // 非空校验
  if (username === '' || password === '') {
    showToast('用户名和密码不能为空')
    return
  }

  // 长度校验
  if (username.length < 8 || username.length > 30 || password.length < 6 || password.length > 30) {
    showToast('用户名的长度为8-30,密码的长度为6-30')
    return
  }

  // 2. 数据提交
  try {
    // .post 请求方法 post,参数1:请求URL,参数2:提交的数据
    const res = await axios.post('/register', { username, password })
    // console.log(res)
    showToast(res.message)
  } catch (error) {
    // console.dir(error)
    showToast(error.response.data.message)
  }

})

易错点:username.length 判断前要确保 username 是字符串;长度边界要包含等于 8/30、6/30 的情况;校验失败必须 return。

提交数据与处理结果 ​

为什么需要:请求可能成功也可能失败,必须给用户提示。
怎么想:用 axios.post('/register', { username, password }) 提交,成功走 try,失败走 catch。
怎么做:按笔记代码,成功提示取 res.message;失败提示取 error.response.data.message。调试时先打印 res 或 console.dir(error) 确认数据结构。
易错点:成功和错误的数据层级不同,不能混用;catch 里要防止 error.response 不存在导致二次报错。

调试细节:提示与跳转的时序 ​

转写稿中课堂还加了“注册成功后跳转登录页”的戏。调试时发现:如果提示框刚出现就立即 location.href 跳走,用户几乎看不到提示。因此要晚一点跳转,例如延迟 500~800 毫秒,让提示先显示。注意本节笔记代码未包含跳转,实际加跳转时不要破坏原有校验和提交逻辑。
易错点:跳转路径要从 register.html 所在位置出发找登录页;不要因为加跳转把 showToast 写在跳转之后。

Git 记录 ​

为什么需要:每完成一个小功能就提交,方便回退和追踪。
怎么做:

bash
git add .
git commit -m"用户注册"

易错点:提交前先看 git status,确认只提交本次注册相关改动;提交信息写清楚,不要堆积多个功能再提交。

课件图示 ​

课件第55页:配置axios基地址 项目中配置axios基地址,简化后续URL设置(Git记录

课件第56页:抽取轻提示函数 抽取轻提示函数,方便后续调用(Git记录) 抽取轻提示函数 实例

课件第53页:1. 公共逻辑写在common.js 2. 页面逻辑写在js目录下的同名js文件

课件第57页:用户注册 完成用户注册功能,提示用户操作结果(Git记录) 收集并校验数据 数据

课件第10页:文档地址: 安装完Git 之后,要做的第一件事就是设置你的用户名和邮件地址。因为

课件第51页:项目模块 1. 注册业务 2. axios基地址、简化方法 3. toast轻提

课件第17页:文档地址:每当完成了一个阶段的目标,想要记录下它时,就将它提交到仓库。 核心操作

课件第18页:核心操作及命令: 1. 工作区开发 项目文件夹 2. 将修改后的文件添加到暂存区

代码示例 ​

示例一:common.js —— 公共逻辑(axios 基地址 + 轻提示函数) ​

javascript
/**
 * common.js —— 公共逻辑
 * 1. 配置 axios 基地址
 * 2. 抽取轻提示函数
 */

// 1. 配置 axios 基地址:后续相对路径的请求会自动拼上这个前缀
axios.defaults.baseURL = 'https://hmajax.itheima.net'

// 2. 抽取轻提示函数:任意页面调用 showToast('提示信息') 即可显示
function showToast(msg) {
  const toastDom = document.querySelector('.my-toast')
  // 实例化 bootstrap 的 Toast 组件
  const toast = new bootstrap.Toast(toastDom)
  // 修改内容并显示
  document.querySelector('.toast-body').innerText = msg
  toast.show()
}

配套的 HTML 结构(每个页面都必须有,否则 showToast 找不到元素):

html
<!-- 所有页面都准备好了轻提示的结构 -->
<div class="toast bg-rgba my-toast" data-bs-delay="1500">
  <div class="toast-body">提示消息</div>
</div>

关键行与易错点

  • axios.defaults.baseURL 会自动加在 url 前面,除非 url 是绝对地址;所以配置后请求里只写 /register、/login 这类半段地址即可。
  • 基地址配置属于“所有页面都要用”的公共逻辑,必须写在 common.js,不要写在某个页面的 js 里。
  • data-bs-delay="1500" 控制自动关闭时间,写在 HTML 上而不是 JS 里。
  • 易错点:showToast 里的选择器 .my-toast 与 .toast-body 必须和页面结构类名完全一致;实例化 Toast 时传的是 DOM 元素,不是选择器字符串。
  • 易错点:common.js 必须在 register.js 之前引入,否则页面里调用 showToast 会报未定义。

示例二:用户注册(register.html + register.js) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>注册</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
  <div class="container mt-5" style="max-width: 420px;">
    <form class="register-form">
      <div class="mb-3">
        <label class="form-label">用户名</label>
        <input type="text" class="form-control" name="username" placeholder="8-30位字符">
      </div>
      <div class="mb-3">
        <label class="form-label">密码</label>
        <input type="password" class="form-control" name="password" placeholder="6-30位字符">
      </div>
      <button type="button" id="btn-register" class="btn btn-primary w-100">注册</button>
    </form>
  </div>

  <!-- 轻提示结构 -->
  <div class="toast bg-rgba my-toast" data-bs-delay="1500">
    <div class="toast-body">提示消息</div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
  <!-- 提供 serialize 方法(项目模板中已引入,此处以 CDN 为例) -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/index.js"></script>
  <script src="common.js"></script>
  <script src="register.js"></script>
</body>
</html>
javascript
/**
 * register.js —— 用户注册
 *  1. 收集并校验数据
 *  2. 数据提交
 */
document.querySelector('#btn-register').addEventListener('click', async () => {
  // 1. 收集并校验数据
  const form = document.querySelector('.register-form')
  const data = serialize(form, { empty: true, hash: true })
  const { username, password } = data
  console.log(username, password)

  // 非空校验
  if (username === '' || password === '') {
    showToast('用户名和密码不能为空')
    return
  }

  // 长度校验
  if (username.length < 8 || username.length > 30 || password.length < 6 || password.length > 30) {
    showToast('用户名的长度为8-30,密码的长度为6-30')
    return
  }

  // 2. 数据提交
  try {
    // axios 别名方法:.post(请求URL, 提交的数据)
    const res = await axios.post('/register', { username, password })
    showToast(res.message)

    // 注册成功后跳转到登录页:延迟跳转,否则提示框还没看清就跳走了
    setTimeout(() => {
      location.href = './login.html'
    }, 800)
  } catch (error) {
    showToast(error.response.data.message)
  }
})

关键行与易错点

  • serialize(form, { empty: true, hash: true }):empty: true 表示空值也要收集,hash: true 表示返回对象(接口要 JSON 对象,不要数组格式)。
  • 两段校验里 return 必须写,否则校验失败还会继续往下发请求。
  • axios.post(url, data) 是别名方法,等价于 axios({ url, method: 'post', data }),参数 2 直接对应 data 属性。
  • async 修饰回调、await 修饰请求,才能在原地拿到返回结果;否则要用 .then。
  • 失败时数据在 error.response.data.message,不是 error.message,直接取 error.message 会拿不到后端提示。
  • 跳转路径要以 当前 HTML 页面(register.html)所在位置为基准写 ./login.html,不是以 js 文件位置为基准。
  • 易错点:按钮若写成 type="submit" 放在 form 里会触发表单默认提交导致刷新,这里用 type="button" + 点击事件。

示例三:项目初始化与分支操作(Git 命令) ​

bash
# 1. 在“黑马就业数据平台”文件夹下打开 git bash / 终端,初始化本地仓库
git init

# 2. 拷贝基础模板所有内容后,记录第一次提交
git add .
git commit -m"初始化"

# 3. 创建并切换到 dev 分支(-b 即 branch,创建 + 切换一步完成)
git checkout -b dev

# 4. 配置 axios 基地址后记录
git add .
git commit -m"配置axios基地址"

# 5. 抽取轻提示函数后记录
git add .
git commit -m"抽取轻提示函数"

# 6. 用户注册功能完成后记录
git add .
git commit -m"用户注册"

关键行与易错点

  • git init 必须在项目文件夹内部执行,生成 .git 隐藏目录才算成功。
  • git add . 把工作区改动放入暂存区,git commit -m"..." 才真正写入版本库,两步不能合并省略。
  • git checkout -b dev 等价于“git branch dev + git checkout dev”,是创建并切换一条命令搞定;分支名一般用 dev(develop 的简写)。
  • 每完成一个小功能就提交一次,提交信息写清做了什么,方便后续回退和查看历史。
  • 易错点:-m 和引号之间不要漏空格;切回主分支时用 git checkout master,注意 git checkout 后面直接跟分支名是“切换”,加 -b 才是“创建并切换”。

常见错误 ​

1. git checkout -b dev 敲成了 git branch -b dev,人还在 master 上写代码

  • 现象:git branch 里能看到 dev,但后面几次提交全落在 master 上,切到 dev 发现代码"凭空消失"。
  • 原因:branch 只创建不切换,-b 是 checkout/switch 的参数,敲错了要么报错被忽略,要么静默建了个分支人就走了。
  • 修法:用 git checkout -b dev(或 git switch -c dev),执行完立刻 git branch 看一眼星号在谁身上,再动手写第一行代码。

2. 删除分支报 The branch 'dev' is not fully merged,以为分支坏了

  • 现象:git branch -d dev 删不掉,红字提示 not fully merged。
  • 原因:小写 -d 是安全删除,Git 发现该分支的提交没并进当前分支,怕你丢代码所以拦住了。
  • 修法:确实不要了就 git branch -D dev 强制删除;想留代码就先 git merge dev 再删。强删前用 git log dev 确认一下里面没有你还要的东西。

3. 冲突文件改完了,却一直卡在 |MERGING 状态

  • 现象:分支名后面永远跟着 |MERGING,git checkout master 被拒绝,git status 一片红。
  • 原因:把"编辑文件"当成了"解决冲突"。合并是一个事务,只改文件不暂存不提交,事务没结束。
  • 修法:删干净 <<<<<<< / ======= / >>>>>>> 三类标记 → git add . → git commit -m "解决冲突" → git status 确认 working tree clean 再干别的。

4. 配了 baseURL,请求却打到了 https://hmajax.itheima.netlogin

  • 现象:接口 404,或者 Network 里地址明显拼接错了。
  • 原因:baseURL 结尾和 url 开头都没斜杠,axios 是直接字符串相加;另一种是把完整绝对地址写进 url,baseURL 被整个忽略。
  • 修法:baseURL 写 https://hmajax.itheima.net(不带尾斜杠),业务里 url 一律以 / 开头;改完必须开 F12 Network 看一次真实请求地址。

5. 调用 showToast() 报 Cannot read properties of null (reading 'innerText')

  • 现象:点注册按钮毫无反应,控制台一片红。
  • 原因:该页面没引 common.js,或者页面里缺 .my-toast 那段结构(复制页面时漏了)。
  • 修法:确认每个页面 common.js 的 script 标签在业务 js 之前;补齐 toast DOM;函数内部先取元素判空再操作,别假设结构一定存在。

6. 注册成功提示一闪而过,根本看不清

  • 现象:跳是跳到登录页了,但 toast 没看见。
  • 原因:location.href 是立即跳转,页面一卸载,toast 的 1.5s 延时自然失效。
  • 修法:setTimeout(() => { location.href = './login.html' }, 800)。另外路径是从当前 HTML 页面出发算的,不是从 js 文件所在目录算——这条错了就是 404。

7. 只填密码不填用户名,.length 直接报错

  • 现象:serialize 出来的 username 是 undefined,判空逻辑没生效,下一行 .length 崩了。
  • 原因:serialize 没加 empty: true,空值字段被整体跳过,对象里压根没这个 key。
  • 修法:serialize(form, { hash: true, empty: true }),并且判空用 !username 而不是 username === ''。

8. 断网时错误提示不出来,控制台又多一个红错

  • 现象:请求失败,toast 没弹,error.response.data.message 报 TypeError。
  • 原因:网络错误、超时这类情况根本没有 response 对象。
  • 修法:showToast(error.response?.data?.message || '网络异常,请稍后重试'),成功路径和失败路径都要能兜住。

练习 ​

练习 1|分支命令组合拳 从初始化好的仓库出发,完成:创建并切换到 dev → 在 dev 上改一个文件并提交一次 → 切回 master → 用 -d 删 dev 观察报错 → 用 -D 强删。把完整命令序列写进笔记,并在每一步后执行 git branch 记录星号位置。

练习 2|亲手制造并解决一次冲突 在 master 和 dev 上分别修改 index.html 的同一行,git merge 触发冲突后,用 VS Code 的四个选项各处理一次(至少覆盖"采用当前更改"和"采用传入的更改"),每次都走完 add + commit。对比两种选择下最终文件内容的差异。

练习 3|baseURL 生效边界验证 在 common.js 配好基地址后,分别发三个请求:url 写 /login、写 login(无斜杠)、写 https://hmajax.itheima.net/login(绝对地址)。在 Network 面板记录三次的真实请求地址,写一句话总结 baseURL 什么时候加、什么时候不加。

练习 4|showToast 的健壮性加固 把 showToast 同时用到注册页和登录页。然后故意删掉注册页里的 .my-toast 结构复现报错,再给函数加上"取不到元素时 console.warn 并 return"的保护。提交两次 Git 记录,一次复现、一次修复。

练习 5|注册业务测试用例表 完成注册功能后,设计至少 6 组用例并逐条验证:用户名空、密码空、用户名 7 位、用户名 8 位(边界)、用户名 31 位、密码 5 位、全部合法。用表格记录"输入 → 预期提示 → 实际提示",标出所有不符合预期的行并修复。

原视频对照 ​

#视频时长
1Git分支操作-命名补充06:46
2Git分支操作-冲突12:49
3day01-Git&黑马就业数据平台-12项目演示及初始化06:35
4项目-配置axios基地址08:20
5项目-抽取提示框框组件05:31
607-07-17-57-4316:46
707-07-19-50-1317:31

小结 ​

  1. Git 的真正价值不是"能提交",而是小步提交——每完成一个可验证的小功能就 add + commit,出问题才有干净的退路。
  2. 主分支是基线,功能开发一律在 dev 上进行。-b 创建并切换、-D 强制删除,前者要验证星号位置,后者要确认代码真的不要了。
  3. 冲突的本质是"同一文件同一位置的不同修改",它不可避免也不可怕;解决冲突是一个完整事务:改文件 → add → commit,少一步就一直卡在 MERGING。
  4. 公共能力(baseURL、showToast)一律沉到 common.js,页面 js 只写业务。抽取得越早,后面复制粘贴带出来的错就越少。
  5. 静态页面项目里,相对路径永远从当前 HTML 页面出发,不是从 js 文件所在目录出发——这是最高频的踩坑点。
  6. 异步流程必须写 try/catch,并且错误提示要防 response 为空;只写成功路径的代码在真实网络环境下等于没写。
  7. 所有"看不出来为什么"的问题,先去 F12 的 Network 和 Console 里找证据,再回来改代码——猜是效率最低的调试方式。