黑马Vue_day12(一):getters,怎么看 Apifox 文档,工程化等工具介绍;

第1个

getters

在 Vuex 或 Pinia(Vue 的状态管理库)中,Getters 可以简单理解为 "状态仓库(Store)里的计算属性(Computed)"

它的核心作用是:基于已有数据(State)派生/计算出新的数据 ,并且具备缓存特性

一、 为什么需要 Getters?

假设你的状态仓库(Store)里存了一个用户列表数据 users

JavaScript

yaml 复制代码
state: {
  users: [
    { id: 1, name: '张三', age: 16 },
    { id: 2, name: '李四', age: 22 },
    { id: 3, name: '王五', age: 19 }
  ]
}

如果你在 项目里的 5 个不同页面 中,都需要获取"所有成年用户(age >= 18)",你该怎么办?

  • 不用 Getters :你需要在 5 个页面组件里分别写 filter 逻辑去过滤数据。万一以后"成年"的判定标准改成了 20 岁,你需要手忙脚乱地去修改 5 个页面的代码。

  • 使用 Getters :把"过滤成年人"的逻辑抽离并写在 Store 的 getters 中,所有页面直接读取这一个 Getter 结果即可。实现一次定义,处处共享

二、 Getters 的三大核心特性

  1. 响应式与缓存:只要它依赖的 State 数据没有发生改变,多次读取同一个 Getter 会直接从缓存中取值,无需重复计算,性能极高。

  2. 逻辑集中:将数据的二次加工/计算逻辑统一收拢在 Store 内部,不把脏逻辑留在页面组件中。

  3. 只读性 :Getters 计算出的数据是只读的,不能直接修改,只能通过修改它依赖的底层的 State 数据来间接更新。

三、 在 Vuex 与 Pinia 中的代码示例

1. 在 Vuex 中定义与使用

JavaScript

php 复制代码
// 在 store/index.js 中定义
const store = createStore({
  state: {
    users: [
      { id: 1, name: '张三', age: 16 },
      { id: 2, name: '李四', age: 22 }
    ]
  },
  getters: {
    // 1. 基本用法:第一个参数默认就是 state
    adultUsers: (state) => {
      return state.users.filter(user => user.age >= 18)
    },
    // 2. 传参用法(返回一个函数):根据动态参数筛选
    getUserById: (state) => (id) => {
      return state.users.find(user => user.id === id)
    }
  }
})

在组件内部调用:

JavaScript

javascript 复制代码
import { computed } from 'vue'
import { useStore } from 'vuex'

const store = useStore()

// 读取 getters 数据
const adultList = computed(() => store.getters.adultUsers)
// 调用可以传参的 getter
const userTwo = computed(() => store.getters.getUserById(2))
2. 在 Pinia(现代 Vue 3 推荐)中定义与使用

在 Pinia 中,Getters 的语法更加直观,直接使用 this 即可读取同一 store 下的各种数据:

JavaScript

javascript 复制代码
// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    users: [
      { id: 1, name: '张三', age: 16 },
      { id: 2, name: '李四', age: 22 }
    ]
  }),
  getters: {
    // 可以直接使用 this 访问当前 state 或其他 getter
    adultUsers() {
      return this.users.filter(u => u.age >= 18)
    }
  }
})

在组件内部调用:

JavaScript

javascript 复制代码
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()

// 直接点出来使用,天然保持响应式
console.log(userStore.adultUsers)

四、 快速记忆总结

概念/属性 Vue 基础概念 Vuex / Pinia 中的对应概念
存储原始数据 组件的 data() / ref() state
计算衍生数据 组件的 computed getters
同步修改数据 组件的 methods mutations(Pinia 已废弃,合并入 Actions)
异步/业务逻辑 组件的 methods actions

第2个

怎么看 Apifox 接口文档

一、 第一步:确定地址,接口类型功能

区域标识 含义与关注点 大白话解读
接口名称 接口是干嘛的(如:"用户登录"、"获取文章列表")。 知道了这个接口的功能。
请求方式 (Method) 常见的有 GET / POST / PUT / DELETE / PATCH 告诉你用哪种"动作"发请求。 • GET :查数据(拿菜单) • POST :提交新数据(提交订单) • PUT/PATCH :修改数据(修改备注) • DELETE:删除数据(取消订单)
接口路径 (URL/Path) 比如 /api/user/login 接口的相对路径。结合左上角/顶部的前置 URL (基准地址,如 [https://api.example.com](https://api.example.com)),拼接起来就是完整的请求地址

二、 第二步:看"请求参数 (Request)"(你必须给后台什么)

这是整个文档最重要的部分之一。它决定了你前端需要用表单收集哪些数据传给后台。

Apifox 里的请求参数通常分为以下几种标签页(Tabs):

1. Header(请求头)

  • 看什么:传给服务器的"附加身份信息"。

  • 常见字段Authorizationtoken(用来证明你登录了)。

  • 小白注意:很多需要登录才能调用的接口,文档里会注明需要在 Header 传 Token。

2. Params / Query(查询参数)

  • 看什么 :通常出现在 GET 请求 中,参数会直接拼在网址后面(如 /search?keyword=vue&page=1)。

  • 表格关键列

    • 参数名:写代码时传的键(Key)。

    • 是否必填:带有红点或写着"必填"的,不传后台就会报错。

    • 类型string(文本)、integer/number(数字)等。

    • 说明/示例:告诉你这个参数是干嘛的(如:"页码,默认1")。

3. Body(请求体)

  • 看什么 :通常出现在 POST / PUT / PATCH 请求 中,用来提交大量或复杂的数据。

  • 数据格式类型

    • json(最常见) :格式形如 {"username": "admin", "age": 18}

    • form-data :常用于文件上传(带图片/文档)或普通表单。

    • x-www-form-urlencoded:传统的表单格式。

三、 第三步:看"返回参数 / 响应数据 (Response)"(后台会给你什么)

当你的请求发过去后,后台会给你吐出一段 JSON 数据。这里展示了数据的结构规范

1. HTTP 状态码(如 200 OK)

  • 200 表示网络请求成功到达了服务器。

2. 响应 Body(数据结构)

后台返回的 JSON 数据通常遵循统一的"三段式"套路:

JSON

json 复制代码
{
  "code": 0,          // 1. 业务状态码(注意:非 HTTP 状态码,通常 0 或 200 代表业务成功)
  "message": "success",// 2. 提示信息(如:"登录成功" 或 "密码错误")
  "data": { ... }     // 3. 核心数据(具体的业务对象、列表等)
}
  • 怎么看树状结构表格?

    在 Apifox 中,返回参数也是以表格形式列出的。如果 data 是一个对象,下面缩进展开的就是 data 内部的属性字段(比如 data.tokendata.userInfo.nickname)。你写页面渲染时,就从 data 里面拿对应的字段名。

四、 第四步:看"请求示例代码 / 示例"(拷贝即用)

Apifox 页面右侧(或下方)通常有巨大的效率神器:

  1. 示例(Examples / 响应示例)

    • 包含"成功示例"和"失败/异常示例"。

    • 作用:直观地展示真实的返回数据长什么样。前端写 Mock 数据或者对接口时直接看这个最快。

  2. 生成代码 (Generate Code)

    • Apifox 可以自动将当前接口转换为各种语言的代码片段!

    • 切换到 JavaScript -> AxiosFetch,复制代码直接贴到你的 Vue/React 项目里就能跑。

五、 第五步:使用"调试 (Apifox 核心优势)"(在线测试接口)

如果你不确定接口好不好使,或者后台有没有开发完,不需要写任何代码 ,直接点击页面的 "调试" 按钮(或标签页):

  1. 在参数输入框里填入测试数据(如用户名 test,密码 123456)。

  2. 点击右侧鲜艳的 "发送 (Send)" 按钮。

  3. 观察下方出来的 "响应结果 (Response)"

    • 如果返回了符合预期的 JSON,说明后台接口是通的,参数没问题。

    • 如果报错(如 404 地址错了,401 没登录,500 后台报错),你可以拿着错误信息直接找后台沟通。

💡 小白看文档速记指南(5 步走)

当你接到一个新接口任务时,按这个顺序看:

  1. 看名字和动作 :这是啥接口?用 GET 还是 POST

  2. 看请求地址:完整 URL 是什么?

  3. 看必填参数 :是在 Params 还是在 Body?哪些字段写着必填

  4. 看返回结果 :成功时 code 是多少?要拿的数据在 data 的哪个字段里?

  5. 点"调试"测一下:点发送按钮自己调一次,看到真实返回数据心里就有底了。

第3个

prettier,eslint,husky,pnpm

Prettier 是一款开源的代码格式化工具(Opinionated Code Formatter)。它的主要作用是自动重新排版你的代码,使其遵循统一、规范的视觉风格。

1. 它解决什么问题?

在团队开发或个人编写代码时,经常会出现以下痛点:

  • 缩进与风格混乱:有人习惯 2 个空格,有人习惯 4 个空格;有人喜欢单引号,有人喜欢双引号。

  • 无谓的争论:在 Code Review(代码审查)中,开发者常为"大括号要不要换行"、"句末要不要加分号"等格式细节争吵,浪费时间。

  • 手动对齐低效:手动调整换行和缩进既繁琐又容易出错。

Prettier 接入后,开发者只需保存文件(Ctrl + S / Cmd + S),代码就会自动变整洁,无需人工干预。

2. 主要特性

  • 强主见(Opinionated) :Prettier 故意只保留极少数可配置项(如缩进宽度、单双引号、句末分号等)。它的理念是"放弃争议,接受统一",直接帮你决定绝大多数格式规则。

  • 语法感知(Syntax-Aware) :它不是简单的正则替换,而是先将代码解析为抽象语法树(AST),擦除原有的所有格式,再根据当前行宽(Line Length)重新优雅地打印出来。如果一行太长,它会自动拆分成多行。

  • 多语言支持:原生支持 JavaScript、TypeScript、JSX、CSS/SCSS/Less、HTML、Vue、Angular、JSON、Markdown、YAML、GraphQL 等。

3. Prettier vs. ESLint 的区别

许多初学者容易混淆两者的定位:

工具 主要职责 关注重点 示例
Prettier 格式化 (Formatting) 代码"长得好看" 最大行宽、缩进空格数、单双引号、末尾逗号
ESLint 代码质量 (Linter) 代码"写得正确" 检查未使用的变量、未处理的 Promise、禁止潜在 Bug 的写法

最佳实践:通常在项目中同时使用两者,用 ESLint 检查代码质量,用 Prettier 负责纯粹的格式化。

4. 常见使用场景

  1. 编辑器插件 :在 VS Code 或 WebStorm 中安装 Prettier 插件,开启 Format On Save(保存时自动格式化)。

  2. Git Hook (Husky / lint-staged) :在提交代码(git commit)时自动运行 Prettier,确保提交到仓库的代码始终保持规范。

  3. CI/CD 流水线:在自动化构建流程中检查代码格式是否合规。

husky和pnpm

Huskypnpm 是前端工程化体系中非常核心的两个工具。简单来说:

  • pnpm 负责管理项目依赖(比 npm/yarn 更快、更省空间)。

  • Husky 负责拦截 Git 操作(在提交代码前自动运行检查或格式化)。

下面分别拆解它们的核心作用与使用场景:

1. pnpm:新一代高效包管理器

pnpm(Performance npm)是一个旨在替代 npm 和 yarn 的 JavaScript 包管理工具。

核心优势

  • 极其节省磁盘空间(硬链接 + 软链接)

    • 传统 npm/yarn :每个项目安装依赖时,都会在本地磁盘的 node_modules 中下载一套完整的副本。如果有 10 个项目都用了 React,磁盘上就会有 10 份相同的 React 文件。

    • pnpm :会将所有依赖全局存储 在本地的一个"全局内容寻址存储库(Global Store)"中。项目中的 node_modules 只是指向全局 Store 的硬链接(Hard Link)软链接(Symbolic Link) 。无论创建多少个项目,同一版本的包在磁盘上永远只占一份空间。

  • 安装速度极快

    因为避免了重复下载和复杂的复制文件过程,安装依赖的速度通常是 npm 和 yarn 的数倍。

  • 严格的依赖隔离(解决"幽灵依赖"问题)

    • 在 npm/yarn 中,依赖会被"扁平化 (Flat)"展开到 node_modules 根目录。即使你的 package.json 只声明了 A 包,但如果 A 包依赖了 B 包,你依然可以在项目中直接 import B(即幽灵依赖)。一旦 A 包未来删除了对 B 的依赖,你的项目就会崩溃。

    • pnpm 通过符号链接构建非扁平的 node_modules 结构,项目只能引用在 package.json 中明确声明过的依赖,大幅提升代码安全性。

  • 原生支持 Monorepo(多包/多项目管理)

    pnpm 内置了 pnpm-workspace.yaml,不需要额外安装复杂工具就能轻松在一个仓库里管理多个子项目。

1. 什么是"扁平化(Flat)"?

在早期的 npm (v2) 中,依赖是嵌套 安装的。如果你的项目依赖 A,A 依赖 B,node_modules 结构会像套娃一样:

Plaintext

css 复制代码
node_modules/
  └── pkg-A/
      └── node_modules/
          └── pkg-B/

这种结构会导致目录层级极深、路径过长(在 Windows 上经常报错),且大量的包会被重复下载。

为了解决这个问题,npm v3+ 和 yarn 引入了"扁平化(Flat)"策略:不管这个包是你直接引用的,还是你依赖的包引用的,通通提拔到 node_modules 的最顶层

于是,目录结构变成了这样:

Plaintext

css 复制代码
node_modules/
  ├── pkg-A/  <-- 你声明的依赖
  └── pkg-B/  <-- A 依赖的包,被平铺到了最外层!

2. Node.js 的模块查找机制

当你在代码里写 import B from 'pkg-B' 时,Node.js 会去哪里找 pkg-B 呢?

它的查找规则非常简单:直接去离当前文件最近的 node_modules 根目录下找名为 pkg-B 的文件夹。

既然因为"扁平化",pkg-B 已经被放到了 node_modules 的根目录下,Node.js 就能顺手把它查出来,代码就能正常运行并打印数据!

3. 为什么这被称为"幽灵依赖"?

你的 package.json(类似于你的采购清单)里明明只写了依赖 pkg-A

JSON

css 复制代码
{
  "dependencies": {
    "pkg-A": "^1.0.0"
  }
}

按照规范,你只应该 在代码里 import A

但是,因为扁平化把 pkg-B 偷摸放到了根目录,你居然可以在代码里直接 import B from 'pkg-B',而且程序还能正常运行!

这个 pkg-B 就像一个未被记录、却幽灵般存在 的依赖------这就是幽灵依赖

4. 致命危险:为什么说"项目会崩溃"?

你可能会想:"能直接用不是挺好的吗?我还少写了一个 pnpm add pkg-B。"

危险发生在未来 pkg-A 升级的时候:

  1. 今天pkg-A 的作者更新到了 v2.0,重构了代码,觉得 pkg-B 不好用,删掉了对 pkg-B 的依赖。

  2. 明天:C 本来也用了 B,但是因为之前幽灵依赖安装了,不会报错;但A如果不再用B,那么重新npm install就不会有B,而package.json一直没有声明B,C import B就会报错。

  3. 结果

    • npm 重新计算依赖,发现没有任何包再依赖 pkg-B 了。

    • npm 在安装时就会node_modules/pkg-B 彻底删掉

    • 当你的代码运行到 import B from 'pkg-B' 时,直接报红崩溃:Cannot find module 'pkg-B'(找不到模块)。

5. pnpm 是如何解决这个问题的?

pnpm 不采用简单粗暴的"把所有包平铺在根目录"的方式,而是使用了软链接(Symlink,新inode编号,存数据地址)结构:(总之就是不flat,声明什么安装什么)

Plaintext

css 复制代码
node_modules/
  ├── .pnpm/                <-- 真实的包全在这里
  └── pkg-A/                <-- 根目录下只放你 package.json 里声明的 pkg-A
  • 你的 node_modules 根目录下,只有你在 package.json 里写的 pkg-A

  • pkg-B 被隐藏在 .pnpm 的深层结构中。

  • 如果你在代码里尝试 import B from 'pkg-B',Node.js 在 node_modules 根目录下找不到 pkg-B在开发阶段就会直接报错提示你未安装该依赖,从而将隐患直接扼杀在摇篮里!

在操作系统中,硬链接(Hard Link)软链接(Symbolic Link / Symlink,即符号链接/快捷方式)是两种指向文件的指针机制。

要彻底搞懂它们,我们需要先了解操作系统是如何存储文件的:

在 Linux/Unix 文件系统中,一个文件由两部分组成:

  1. 数据块(Data Block) :真正存储文件内容的地方(比如硬盘上的具体二进制数据)。

  2. 索引节点(Inode,Index Node) :存储文件的元数据(如文件大小、创建时间、文件所有者等)以及指向数据块的指针。每个文件都有一个独特的 Inode 编号。

而我们平常看到的"文件名",本质上只是一个映射关系(类似钥匙) ,指向对应的 Inode。

1. 硬链接(Hard Link)

硬链接本质上是为同一个 Inode 编号创建了一个新的文件名

  • 原理 :创建一个硬链接,就像是给同一个文件起了个"别名/名片"。原文件名和硬链接文件名指向的是同一个 Inode ,对应同一份物理数据

  • 特点

    • 删除不影响:因为两个文件名指向同一个 Inode,删除原文件,只是删除了其中一条"映射"。只要还有一个硬链接存在,文件数据就不会丢失。

    • 完全平级:原文件和硬链接在地位上没有任何区别,无法区分谁是"原始文件"。

    • 不占额外空间:因为没有创建新的数据块,只是多了一个映射名称。

  • 局限

    • 不能跨文件系统/跨磁盘分区创建。

    • 不能为目录(文件夹)创建硬链接(防止形成无限循环的目录环路)。

💡 现实比喻:

给一个人起小名。张三(原文件名)的小名叫三儿(硬链接)。无论是找到"张三"还是"三儿",指的都是同一个人(物理数据)。哪怕把"张三"这个名字废弃了,"三儿"这个人依然真实存在。

软链接相当于 Windows 系统里的"桌面快捷方式"。

  • 原理 :软链接本身是一个全新的独立文件,它有自己独立的 Inode 编号 。软链接的数据块里不存具体内容,而是专门存储目标文件的绝对或相对路径字符串

  • 特点

    • 依赖原路径:当访问软链接时,系统会读取软链接里记录的路径,然后再去寻找原文件。

    • 原文件删除即失效:如果删除了原文件(或者把原文件重命名/移动了),软链接就会变成一个找不到目标的"死链接(Broken Link)"。

    • 功能更广泛:可以跨文件系统创建,也可以为目录(文件夹)创建软链接。

  • 局限

    • 会占用极小的物理空间(用于保存目标路径字符串)。
💡 现实比喻:

一张纸条上写着:"请前往北京市朝阳区建国门外大街1号"。你顺着纸条上的地址找到那栋楼(原文件)。如果那栋楼被拆了(原文件被删),纸条(软链接)还在,但你顺着地址找过去只能找到一片废墟。

3. 对比总结表

特性 硬链接 (Hard Link) 软链接 (Soft Link / Symlink)
本质 同一 Inode 的额外文件名(别名) 一个指向目标路径的新文件(快捷方式)
Inode 编号 与原文件 相同 与原文件 不同
删除原文件 数据仍可用,可以通过硬链接访问 软链接报废(死链接)
是否支持目录 ❌ 不支持

2. Husky:Git Hooks 自动化管理工具

Husky 专门用来简化 Git Hooks(Git 钩子) 的配置与管理。

核心作用与场景

Git 提供了许多原生钩子(例如在 git commitgit push 时触发的脚本),但默认情况下,.git/hooks 文件夹下的配置无法同步提交到 Git 远程仓库。这意味着你无法让团队里的每个成员都自动共享这些检查规则。

Husky 的作用就是将 Git Hooks 的配置纳入版本控制,让团队所有人在 clone 项目并运行安装脚本后,自动具备相同的 Git 检查机制。

常见的配合链条(最佳实践)

Husky 通常不单独工作,而是与 lint-stagedPrettierCommitlint 协同作业:

  1. 提交前自动格式化(pre-commit 钩子)

    • 流程 :当你输入 git commit 时,Husky 触发 pre-commit 钩子。

    • 动作 :借助 lint-staged (只针对本次 git add 暂存区的文件进行检查,提升速度),自动运行 Prettier 格式化代码,运行 ESLint 检查错误。如果检查不通过,直接中断提交。

    • 结果:保证进入 Git 历史的代码永远是格式化且无语法错误的。

  2. 规范 Commit 信息格式(commit-msg 钩子)

    • 流程 :在输入提交信息时,Husky 触发 commit-msg 钩子。

    • 动作 :调用 Commitlint 校验你的提交日志格式是否符合规范(如 feat: 新增登录功能fix: 修复首页卡顿)。

    • 结果 :防止出现 git commit -m "fix"git commit -m "111" 这种无意义的提交记录。

3. 三者(Prettier + Husky + pnpm)在实际项目中的组合工作流

在一个标准的现代前端项目中,它们通常是这样协同工作的:

  1. 你使用 pnpm 安装依赖并管理项目的开发环境。

  2. 你修改了代码并保存,Prettier 插件在编辑器内帮你完成初步格式化。

  3. 你执行 git add . 将更改加入暂存区。

  4. 你执行 git commit -m "feat: 新增首页图表"

  5. Husky 拦截该提交,触发 pre-commitcommit-msg 钩子:

    • 对暂存区的代码再次运行 Prettier 和 ESLint,防止漏网之鱼。

    • 检查 commit 信息是否规范。

  6. 校验通过,提交成功;若校验失败,终端报错并阻止提交,等待你修改后再提交。

第4个

两种路由模式

在 Web 开发(特别是 Vue Router、React Router 等单页面应用 SPA 框架)中,最常用的两种客户端路由模式是:Hash 模式History 模式

它们的核心目的都是:在改变浏览器 URL 的同时不刷新页面,并通过监听 URL 变化来动态渲染对应的视图组件。

1. Hash 模式

Hash 模式的 URL 中会带有一个 # 符号(例如:[https://example.com/#/user/profile](https://example.com/#/user/profile))。

📌 基本使用

在配置路由时直接指定模式为 hash(Vue Router 3 示例:mode: 'hash',Vue Router 4 示例:createWebHashHistory())。

⚙️ 实现原理
  • URL 特性# 及其后面的内容被称为 URL Hash(锚点) 。HTTP 请求在发送给服务器时,浏览器会自动忽略 # 后面的部分 。因此,无论 # 后面的路径怎么变,发送给服务器的永远是根路径 (如 [https://example.com/](https://example.com/))。

  • 核心 API 与事件

    • 改变路径 :通过修改 location.hash = '/user/profile' 或点击带有 #<a> 标签来切换路由,这会向浏览器的历史记录栈压入一条新记录。

    • 监听变化 :浏览器提供了原生的 hashchange 事件。当 URL 中的 # 后面部分发生变化时(无论是点击链接、调用 API 还是点击浏览器的前进/后退按钮),就会触发该事件:

      JavaScript

      javascript 复制代码
      window.addEventListener('hashchange', () => {
        // 获取当前的路由路径:location.hash
        const currentPath = window.location.hash.slice(1);
        // 根据 currentPath 匹配并渲染对应的视图组件
        renderView(currentPath);
      });
👍 优缺点
  • 优点 :兼容性极佳(支持老旧浏览器);不需要后端/服务器做任何特殊配置,直接部署静态资源即可运行。

  • 缺点 :URL 中带 #,不够美观;锚点功能(如页面内滚动定位 #section1)会被占用;在某些第三方授权回调或 SEO 抓取时可能受到限制。

2. History 模式

History 模式基于 HTML5 引入的 History API,它的 URL 和传统的多页面网站完全一致(例如:[https://example.com/user/profile](https://example.com/user/profile)),没有 # 符号。

📌 基本使用

在配置路由时指定模式为 history(Vue Router 3 示例:mode: 'history',Vue Router 4 示例:createWebHistory())。

⚙️ 实现原理
  • 核心 API 与事件

    • 改变路径但不刷页面 :利用 HTML5 提供的 history.pushState()history.replaceState() 方法。这两个 API 可以在修改浏览器地址栏 URL 的同时,不向服务器发送 HTTP 请求,也不触发页面刷新

      JavaScript

      php 复制代码
      // 改变 URL 并添加历史记录,但不刷新页面
      history.pushState({ page: 'profile' }, 'Profile Title', '/user/profile');
      // 此时地址栏变为 https://example.com/user/profile
    • 监听前进/后退 :当用户点击浏览器的前进/后退按钮 或调用 history.back() / history.forward() 时,会触发 popstate 事件:

      JavaScript

      javascript 复制代码
      window.addEventListener('popstate', (event) => {
        // 获取当前路径:location.pathname
        const currentPath = window.location.pathname;
        // 根据 currentPath 渲染视图
        renderView(currentPath);
      });
    • 注意pushState()replaceState() 本身不会 触发 popstate 事件,因此前端路由库(如 Vue Router)会在重写这两个方法或调用路由跳转逻辑时,手动去更新视图。

⚠️ 致命点与服务器配置(非常重要)

因为 History 模式的 URL 看起来像真实的后端接口路径,如果用户在 [https://example.com/user/profile](https://example.com/user/profile) 页面按 F5 刷新,或者直接复制这个链接在浏览器打开:

  1. 浏览器会直接向服务器发送 GET 请求:/user/profile

  2. 如果服务器上并没有对应 /user/profile 的真实物理文件或路由,服务器就会返回 404 Not Found

解决方案 :需要将服务器(如 Nginx、Apache)配置为兜底重定向 ------ 无论客户端请求什么路径,只要文件不存在,统统返回单页面应用的入口文件 index.html,然后交由前端路由解析路径并渲染视图。

Nginx 配置示例:

Nginx

bash 复制代码
location / {
  try_files $uri $uri/ /index.html; # 找不到文件时,重定向到 index.html
}
👍 优缺点
  • 优点:URL 简洁美观,符合传统网址习惯;符合现代 Web 开发与 SEO 标准。

  • 缺点 :兼容性相对要求高一些(需要 IE10+ 支持 HTML5 History API);必须配合服务器配置兜底重定向,否则刷新即 404。

3. 对比总结

特性 Hash 模式 History 模式
URL 形式 [example.com/#/user](https://example.com/#/user) [example.com/user](https://example.com/user)
核心机制 location.hash + hashchange 事件 history.pushState() + popstate 事件
HTTP 请求 发送请求时自动忽略 # 后面的内容 路径作为真实 URL 发送到后端
服务端配置 不需要额外配置 必须配置 (将所有不存在的路径重定向到 index.html
美观度 较差(带 # 优秀(与传统 URL 无异)
兼容性 极佳(兼容老旧浏览器) HTML5 新特性(支持 IE10+ 及现代浏览器)

第5个

相关推荐
叱咤月海鱼鱼猫1 小时前
iframe 弹窗取消按钮触发父页面弹窗接口
前端
参宿71 小时前
像素vs条数级虚拟列表
前端
paopaokaka_luck2 小时前
基于springboot3+vue3的云南本土影视文旅推荐平台(协同过滤算法、Echarts图形化分析)
前端·spring boot·学习·算法·echarts·mybatis
狂师2 小时前
AI 测试提效 | 别搞万能 Skill,推荐用 5 个 Agent Skill 串起 UI 自动化全流程
前端·人工智能·测试
breeze jiang2 小时前
React useRef 实战:从 input 聚焦到 Web Worker 引用
前端·javascript·react.js
90后的晨仔3 小时前
uni-app 生命周期深度解析(iOS / Android / 鸿蒙 / Vue3 四端对照)
前端
钛态4 小时前
AI 辅助:前端框架反模式:过度封装、状态滥用与副作用失控
前端·vue·react·web
by__csdn4 小时前
Vue vs React vs Angular:前端框架终极对决
前端·vue.js·react.js·前端框架·vue·react·angular