阿卡不拉阿卡不拉
Vue3
阿卡的博客
Vue3
阿卡的博客
  • Vue3

    • 快速入门

      • 搭建工程 👌
      • 模板语法
      • 响应式基础
      • 响应式常用 API
      • 计算属性
      • 类与样式绑定
      • 条件和列表渲染
      • 事件处理
      • 表单处理
      • 生命周期
      • 侦听器
      • 组件介绍
      • Props
      • 自定义事件
      • 组件v-model
      • 插槽
      • 前端路由介绍
      • KeepAlive内置组件
      • 状态管理库
      • 组件库介绍
    • 深入本质

      • 虚拟DOM本质
      • 模板的本质
      • 组件树和虚拟DOM树
      • 数据拦截的本质
      • 响应式数据的本质
      • 响应式的本质
      • 响应式和组件渲染
      • 实现响应式系统 1
      • 实现响应式系统 2
      • 图解EFFECT
      • 实现响应式系统 3
      • 手写computed
      • 手写watch
      • 指令的本质
      • 插槽的本质
      • v-model的本质
      • setup 语法标签
      • 组件生命周期
      • keepalive 生命周期
      • keepalive的本质
      • key的本质
    • 细节补充

      • 【Vue】属性透传
      • 【Vue】依赖注入
      • 【Vue】组合式函数 👌
      • 【Vue】自定义指令
      • 【Vue】插件
      • 【Vue】Transition
      • 【Vue】TransitionGroup
      • 【Vue】Teleport
      • 【Vue】异步组件
      • 【Vue】Suspense
      • 【Router】路由模式
      • 【Router】路由零碎知识
      • 【Router】路由匹配语法
      • 【Router】路由组件传参
      • 【Router】内置组件和函数
      • 【Router】导航守卫
      • 【Router】过渡特效
      • 【Router】滚动行为
      • 【Router】动态路由
      • 【State】通信方式总结
      • 【State】Pinia 自定义插件
      • 【场景】封装树形组件
      • 【场景】自定义 ref 实现防抖
      • 【场景】懒加载
      • 【场景】虚拟列表
      • 【场景】虚拟列表优化
      • 【第三方库】VueUse
      • 【第三方库】vuedragable
      • 【第三方库】vue-drag-resize
      • 【第三方库】vue-chartjs
      • 【第三方库】vuelidate
      • 【第三方库】vue3-lazyload
      • 【场景】Websocket 聊天室
      • 【Vite】✨ 认识 Vite👌
      • 【Vite】配置文件 👌
      • 【Vite】✨ 依赖预构建 👌
      • 【Vite】构建生产版本 👌
      • 【Vite】环境变量与模式
      • 【Vite】CLI
      • 【Vite】Vite 插件
  • 笔面试

    • HTML

      • HTML 面试题汇总
      • 文档声明
      • 语义化
      • W3C 标准组织
      • SEO
      • iframe
      • 微格式
      • 替换元素
      • 页面可见性
    • CSS

      • CSS 面试题汇总
      • CSS 单位总结
      • 居中方式总结
      • 隐藏元素方式总结
      • 浮动
      • 定位总结
      • BFC
      • CSS 属性计算过程
      • CSS 层叠继承规则总结
      • @import 指令
      • CSS3 calc 函数
      • CSS3 媒体查询
      • 过渡和动画事件
      • 渐进增强和优雅降级
      • CSS3 变形
      • 渐进式渲染
      • CSS 渲染性能优化
      • 层叠上下文
      • CSS3 遮罩
    • JavaScript

      • JavaScript 面试题汇总
      • ✨ let、var、const 的区别
      • JS中的数据类型
      • 包装类型
      • 数据类型的转换
      • 运算符
      • ✨ 原型链
      • ✨ this 指向
      • ✨ 垃圾回收与内存泄漏
      • ✨ 执行栈和执行上下文
      • ✨ 作用域和作用域链
      • ✨ 闭包
      • DOM 事件的注册和移除
      • DOM 事件的传播机制
      • 阻止事件默认行为
      • 递归
      • ✨ 属性描述符
      • class 和构造函数区别
      • 浮点数精度问题
      • 严格模式
      • ✨ 函数防抖和节流
      • ✨ WeakSet 和 WeakMap
      • ✨ 深浅拷贝
      • 函数柯里化
      • Node 事件循环
      • 尺寸和位置
    • 浏览器

      • 浏览器面试题汇总
      • ✨ 浏览器的渲染流程
      • ✨ 资源提示关键词
      • 浏览器的组成部分
      • IndexedDB
      • ✨ File API
      • ✨ 浏览器缓存
      • ✨ 浏览器跨标签页通信
      • Web Worker
    • 网络

      • 网络面试题汇总
      • 五层网络模型 👌
      • 常见请求方法 👌
      • ✨cookie👌
      • 面试题
      • 加密
      • ✨JWT👌
      • ✨ 同源策略及跨域问题 👌
      • 文件上传
      • ✨ 输入 url 地址之后
      • 文件下载
      • ✨ session
      • ✨ TCP
      • ✨ CSRF 攻击
      • ✨XSS 攻击 👌
      • ✨ 网络性能优化
      • 断点续传
      • 域名和 DNS
      • SSL、TLS、HTTPS 的关系
      • ✨ HTTP 各版本差异 👌
      • HTTP 缓存协议
      • ✨ WebSocket
    • 工程化

      • CMJ 和 ESM
      • npx
      • ESLint
    • Vue2

      • Vue 面试题汇总相关
      • 组件通信方式总结
      • 虚拟 DOM
      • v-model
      • 数据响应式原理
      • diff
      • 生命周期详解
      • computed
      • 过滤器
      • 作用域插槽
      • 过度和动画
      • 优化
      • keep-alive
      • 长列表优化
      • 其他 API
      • 模式和环境变量
      • 更多配置
      • 更多命令
      • 嵌套路由
      • 路由切换动画
    • Vue3

      • ✨ Vue3 整体变化 👌
      • ✨ Vue3 响应式变化 👌
      • ✨ nextTick 实现原理 👌
      • 两道代码题 👌
      • Vue 运行机制
      • 渲染器核心功能
      • 事件绑定与更新

【Router】路由模式

Vue-router 支持 3 种模式:

  1. Hash 模式
  2. HTML5 模式
  3. Memory 模式

Hash 模式

Hash 是 URL 组成的一部分,例如:

https://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#anchor

其 # 后面的部分就是 Hash 部分。早期 Hash 更多是被用作锚点:

<a href="target">go target</a>
......
<div id="target">i am target place</div>

在上面代码中,点击 <a> 链接,文档会滚动到 id.target 的 div 的位置。

Hash 另一个重要特性:Hash 的变化不会请求服务器

利用该特性可以实现不同 URL 映射不同的模块。

#a —> A

#b —> B

实战:使用 Hash 实现单页应用

// index.js
document.addEventListener("DOMContentLoaded", () => {
    const content = document.getElementById("content");

    const renderPage = (hash) => {
        switch (hash) {
            case "#home":
                content.innerHTML = "<h1>Home</h1>";
                break;
            case "#about":
                content.innerHTML = "<h1>About</h1>";
                break;
            case "#contact":
                content.innerHTML = "<h1>Contact</h1>";
                break;
            default:
                content.innerHTML = "<h1>404</h1>";
        }
    };

    window.addEventListener("hashchange", () => {
        renderPage(window.location.hash);
    });

    renderPage(window.location.hash || "#home");
});
<body>
    <nav>
        <a href="#home">Home</a>
        <a href="#about">About</a>
        <a href="#contact">Contact</a>
    </nav>
    <div id="content"></div>
    <script src="./index.js"></script>
</body>

Vue-router 中如何使用 Hash 模式?

// router/index.js
const router = createRouter({
    history: createWebHashHistory(import.meta.env.BASE_URL),
    routes: [
        // ...
    ],
});

import.meta.env.BASE_URL 是 Vite 里面提供的一个环境变量,默认是应用的根路径

  • 开发环境,默认值是 ‘/’
  • 生产环境,这个值可以在 vite.config.js 里面的 base 中来指定

HTML5 模式

HTML5 模式也被称之为 History 模式。该模式利用 HTML5 的 HistoryAPI 来管理浏览器的历史记录从而实现单页应用。

History API:

  1. history.pushState(state, title, url):将一个状态推入到历史堆栈里面
  2. history.replaceState(state, title, url):替换当前历史堆栈最上面的状态
  3. window.onpopstate:这是一个事件,当用户点击浏览器的前进或者后退按钮的时候,会触发该事件

History 实现原理

工作原理:

  1. 拦截链接点击事件
    • 客户端路由器会拦截页面上的所有链接点击事件(通常是通过阻止链接的默认行为 event.preventDefault( ))
    • 取而代之的是,路由器使用 history.pushState 或 history.replaceState 更新 URL。
  2. URL 变化处理:
    • 当 URL 变化时,路由器会捕捉到这个变化。
    • 路由器不会发出新的 HTTP 请求,而是根据新的 URL 查找预先定义好的路由规则,并加载相应的视图组件

举个例子,假设有一个单页应用,使用 history 模式,并且有以下路由规则:

  • /home: 显示主页内容
  • /about: 显示关于页面内容

当用户点击导航链接从 /home 切换到 /about 时,流程如下:

  1. 用户点击链接 About
  2. 路由器拦截点击事件,调用 event.preventDefault( ) 阻止浏览器的默认行为(即不发出 HTTP 请求)
  3. 路由器调用 history.pushState(null, “”,”/about”) 更新浏览器的地址栏 URL 为 /about
  4. 路由器检测到 URL 变化,查找路由规则,发现 /about 对应的视图组件
  5. 路由器加载并渲染 /about 视图组件,将其插入到页面的特定位置

整个过程中,浏览器地址栏的 URL 更新了,但没有发出新的 HTTP 请求,所有的视图更新都是在客户端完成的。

实战:使用 History 实现单页应用

// index.js
document.addEventListener("DOMContentLoaded", () => {
    const content = document.getElementById("content");

    const renderPage = (path) => {
        console.log(path, "path");
        switch (path) {
            case "/":
            case "/index.html":
                content.innerHTML = "<h1>Home</h1>";
                break;
            case "/about":
                content.innerHTML = "<h1>About</h1>";
                break;
            case "/contact":
                content.innerHTML = "<h1>Contact</h1>";
                break;
            default:
                content.innerHTML = "Not Found";
        }
    };

    document.querySelectorAll("a[data-link]").forEach((link) => {
        link.addEventListener("click", (e) => {
            // 阻止默认事件
            e.preventDefault();
            const path = e.target.getAttribute("href");
            // 推入到浏览器历史记录中
            history.pushState(null, null, path);
            renderPage(path);
        });
    });

    renderPage(window.location.pathname || "/");
});
// index.html
<body>
    <nav>
        <a href="/" data-link>
            Home
        </a>
        <a href="/about" data-link>
            About
        </a>
        <a href="/contact" data-link>
            Contact
        </a>
    </nav>
    <div id="content"></div>
    <script src="./index.js"></script>
</body>

Vue-router 中如何使用 History 模式?

// router/index.js
const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes: [
        // ...
    ],
});

History 存在的问题

一旦刷新,就会报 404 错误。

思考 🤔 为什么会这样?

答案:当你刷新的时候,是会请求服务器的。但是服务器并没有这个后端路由,这个仅仅是一个前端路由。

要解决这个问题,需要在服务器上面做一些配置。添加一个回退路由,如果 URL 不匹配任何的静态资源,回退到首页。

Vue Router

Memory 模式

无论是 Hash 也好、History API 也好,本质上都是基于浏览器的特性来实现的。

而 Memory 模式一般用于非浏览器环境,例如 Node 或者 SSR. 因为是非浏览器环境,所以不会有 URL 交互也不会自动触发初始导航。

该模式用 createMemoryHistory( ) 创建,并且需要在调用 app.use(router) 之后手动 push 到初始导航。

import { createRouter, createMemoryHistory } from "vue-router";
const router = createRouter({
    history: createMemoryHistory(),
    routes: [
        //...
    ],
});
最近更新:: 2025/7/9 07:29
Contributors: AK
Prev
【Vue】Suspense
Next
【Router】路由零碎知识