Vue2下

六:vue-router (重要)

(一). 对路由的理解

1.什么是路由


路由(Router) 是管理页面跳转和 URL 与视图映射关系的机制,核心作用是:根据不同的 URL 路径,展示对应的页面内容,实现单页应用(SPA)的页面切换

一个路由就是一组对应关系(key—value)。
key为路径,value可能是function或component。
在这里插入图片描述

核心概念:

  1. URL 与视图的映射
    路由会将 URL 路径(如 /home/about)与对应的组件(页面)关联起来,当 URL 变化时,自动渲染匹配的组件,而无需刷新整个页面(这是 SPA 的核心特性)。

  2. 单页应用(SPA)的基础
    传统多页应用通过服务器返回不同 HTML 页面实现跳转,而路由让 SPA 能在一个 HTML 页面内,通过切换组件模拟多页效果,提升用户体验(减少加载时间)。

以下是对图片内容的提取与整理,清晰区分后端路由前端路由的核心差异:

2.路由分类

2.1. 后端路由
  • 理解

    • 路由的 value函数,专门处理客户端(如浏览器)的请求。
    • 作用:服务器接收到请求后,通过路径匹配对应的处理函数,返回数据或页面。
  • 工作过程

    1. 客户端(浏览器)发送请求(如 GET /api/users)。
    2. 服务器根据请求路径,找到匹配的函数(如 Node.js 的 app.get('/api/users', (req, res) => { ... }) )。
    3. 函数处理请求(查数据库、拼接数据等),返回响应(如 JSON 数据、HTML 页面)。
2.2. 前端路由
  • 理解

    • 路由的 value组件(component),用于动态展示页面内容(SPA 单页应用的核心)。
    • 作用:在浏览器端实现页面切换,无需刷新整个页面。
  • 工作过程

    1. 浏览器的 URL 路径变化(如从 /home/about)。
    2. 前端路由根据路径变化,匹配对应的组件(如 Vue 中 vue-router 的配置)。
    3. 匹配的组件渲染到页面,实现“局部更新”(无需服务器参与)。
2.3核心差异对比
对比项后端路由前端路由
处理位置服务器端浏览器端
value 类型函数(处理请求、返回响应)组件(展示页面内容)
页面刷新每次请求可能刷新整个页面仅局部更新,无整页刷新
典型技术Node.js(Express)、Java(SpringMVC)Vue Router、React Router
2.4总结
  • 后端路由:负责“服务器如何响应请求”,用函数处理路径并返回数据/页面。
  • 前端路由:负责“浏览器如何切换内容”,用组件匹配路径并局部更新页面。

前端路由是 SPA 应用的基础,让页面跳转像“切换组件”一样丝滑~

3.前端路由的实现原理

主要依赖两种浏览器特性:

  • hash 模式:利用 URL 中的 # 后面的部分(如 http://xxx.com/#/home),hash 变化不会触发页面刷新,通过 onhashchange 事件监听变化。
  • history 模式:使用 HTML5 的 history API(如 pushStatereplaceState),可以修改 URL 且不发送请求,通过 popstate 事件监听变化。

(二).路由高级

  • 嵌套路由(children数组,配置子路由规则,对应组件内用<router-view>显示 )
  • 路由守卫:全局守卫(router.beforeEach )、组件内守卫(beforeRouteEnter等 )、路由独享守卫(beforeEnter ),用于权限校验、导航控制
  • 路由懒加载(component: () => import('./MyRoute.vue') ):优化首屏加载速度

1.嵌套(多级)路由

1.嵌套路由,也叫子路由,是指在一个路由组件中,还可以再嵌套其他的路由组件。在 Vue Router 中,它能够帮助构建更加复杂且层次分明的单页应用结构,让页面的组织和导航更加清晰。

应用场景

当页面存在层级关系时,适合使用嵌套路由。比如电商网站中,商品详情页是一个大的页面,在商品详情页中,又可以有商品介绍、用户评价、相关推荐等子页面,这些子页面就可以通过嵌套路由来实现。

配置步骤(以 Vue Router 在 Vue 项目中的使用为例)
1. 定义路由配置

router/index.js 文件中(假设这是路由配置文件),进行如下配置:

import Vue from 'vue'
import VueRouter from 'vue-router'
import ParentComponent from '../components/ParentComponent.vue'
import ChildComponent1 from '../components/ChildComponent1.vue'
import ChildComponent2 from '../components/ChildComponent2.vue'Vue.use(VueRouter)const routes = [{path: '/parent',component: ParentComponent,children: [{path: 'child1',component: ChildComponent1},{path: 'child2',component: ChildComponent2}]}
]const router = new VueRouter({routes
})export default router

在上述代码中,定义了一个父路由 '/parent',其对应的组件是 ParentComponent。在 children 数组中,又定义了两个子路由 'child1''child2',分别对应 ChildComponent1ChildComponent2

2. 父组件中设置路由出口

ParentComponent.vue 中,需要设置 <router-view> 来显示子路由对应的组件:

<template><div><h1>这是父组件</h1><router-link to="/parent/child1">子组件1</router-link><router-link to="/parent/child2">子组件2</router-link><router-view></router-view></div>
</template>

这里通过 <router-link> 创建了导航链接,点击链接时,会在 <router-view> 中显示对应的子路由组件。

访问嵌套路由

当访问 http://localhost:8080/parent/child1 时,会显示 ParentComponent 的内容,同时在 <router-view> 中渲染 ChildComponent1 的内容;访问 http://localhost:8080/parent/child2 时,则渲染 ChildComponent2 的内容。

嵌套路由的注意事项
  • 子路由路径:子路由的路径不要加 / 开头,否则会被当作根路径。
  • 嵌套层级:可以根据实际需求进行多层嵌套,但层级过深可能会使代码复杂度增加,维护起来更困难。
  • 路由匹配规则:当访问父路由时,如果没有匹配到具体的子路由,<router-view> 中不会渲染任何内容,有时需要设置一个默认子路由来避免这种情况,比如:
{path: '/parent',component: ParentComponent,children: [{path: '', // 空字符串表示默认子路由component: ChildComponent1},{path: 'child1',component: ChildComponent1},{path: 'child2',component: ChildComponent2}]
}

这样,当访问 /parent 时,会默认显示 ChildComponent1 的内容。

通过嵌套路由,可以让单页应用的页面结构更加清晰合理,提升用户体验和代码的可维护性。

2.路由守卫

在 Vue Router 中,路由守卫是一种非常强大的功能,用于在路由跳转的不同阶段对导航进行拦截和控制,例如进行权限验证、记录日志、动态修改路由等。路由守卫主要分为全局守卫路由独享守卫组件内守卫三类。以下是详细介绍:

2.1全局守卫

全局守卫会对应用中所有的路由跳转起作用,主要包括以下三种:

  • router.beforeEach
    • 触发时机:在路由跳转之前,每次路由切换都会触发,并且是全局前置守卫,可以对即将发生的导航进行拦截。
    • 参数:接收三个参数,分别是to(即将要进入的目标路由对象)、from(当前导航正要离开的路由对象)、next(一个函数,必须调用它来resolve这个钩子。执行顺序决定了路由是否继续跳转 )。
    • 示例
const router = new VueRouter({...})router.beforeEach((to, from, next) => {// 模拟权限验证,假设用户登录后才有权限访问除登录页外的其他页面const isLoggedIn = localStorage.getItem('token'); if (to.path!== '/login' &&!isLoggedIn) {next('/login'); // 未登录则重定向到登录页} else {next(); // 允许访问,继续跳转}
})
  • router.beforeResolve
    • 触发时机:在导航被确认之前,在所有组件内守卫和异步路由组件被解析之后,beforeEach 之后触发。主要用于确保在导航确认之前,所有异步操作都已经完成。
    • 参数:和beforeEach 一样,包含tofromnext
    • 示例
router.beforeResolve((to, from, next) => {if (to.meta.requiresAsyncData) {// 假设这里有一个异步获取数据的函数fetchAsyncData(to.params.id).then(() => {next();}).catch(() => {next(false);});} else {next();}
});
  • router.afterEach
    • 触发时机:在路由跳转完成之后触发,没有next 函数,不能对导航进行拦截,主要用于进行一些不需要对导航进行干预的操作,比如记录页面访问日志。
    • 参数:接收两个参数,分别是to(成功跳转的目标路由对象)、from(离开的路由对象)。
    • 示例
router.afterEach((to, from) => {console.log(`${from.path} 跳转到了 ${to.path}`);// 可以在这里调用接口记录页面访问日志等操作
})

在 Vue Router 中,全局守卫是作用于整个应用所有路由的导航钩子,用于统一处理路由跳转的权限验证、日志记录、数据预处理等逻辑。全局守卫分为三类,分别在路由跳转的不同阶段触发,以下是详细解析:

一、全局前置守卫(beforeEach
作用

路由跳转前触发,是全局守卫中最常用的一种,主要用于拦截导航、验证权限、重定向等操作。

触发时机
  • 每次路由切换(包括初始化时的首次加载)都会触发。
  • 执行顺序:在所有组件内守卫和路由独享守卫之前。
参数
  • to:即将进入的目标路由对象(包含路径、参数、元信息等)。
  • from:当前正要离开的路由对象。
  • next:函数,必须调用以决定导航行为:
    • next():允许导航继续。
    • next(false):取消导航,停留在当前页面。
    • next('/path')next({ name: 'routeName' }):重定向到指定路由。
    • next(error):传递错误对象,会被全局错误处理器捕获。
示例(权限验证)
const router = new VueRouter({... })// 全局前置守卫:验证用户是否登录
router.beforeEach((to, from, next) => {// 1. 登录页无需验证,直接放行if (to.path === '/login') {next();return;}// 2. 非登录页:检查是否有登录凭证(如 token)const token = localStorage.getItem('token');if (token) {// 已登录:允许进入目标路由next();} else {// 未登录:强制重定向到登录页next('/login');}
});
二、全局解析守卫(beforeResolve
作用

导航被确认前触发,用于确保所有异步操作(如组件加载、数据请求)完成后再进入目标路由。

触发时机
  • beforeEach 之后,afterEach 之前。
  • 会等待所有组件内守卫和异步路由组件解析完成后才执行。
参数

beforeEach 相同(tofromnext)。

示例(预处理数据)
// 全局解析守卫:确保数据加载完成
router.beforeResolve(async (to, from, next) => {// 如果路由需要预加载数据(通过 meta 标记)if (to.meta.needPreload) {try {// 异步加载数据await fetchData(to.params.id);next(); // 数据加载完成,允许导航} catch (error) {next('/error'); // 加载失败,重定向到错误页}} else {next(); // 无需预加载,直接放行}
});
三、全局后置钩子(afterEach
作用

路由跳转完成后触发,主要用于执行不需要干预导航的操作(如日志记录、页面滚动)。

触发时机
  • 导航已完成,目标组件已渲染。
  • next 函数,无法拦截或修改导航
参数
  • to:成功进入的目标路由对象。
  • from:离开的路由对象。
示例(记录访问日志)
// 全局后置钩子:记录页面访问日志
router.afterEach((to, from) => {// 1. 打印跳转信息console.log(`${from.path} 跳转到 ${to.path}`);// 2. 调用接口记录日志(实际项目中使用 axios 等工具)fetch('/api/log', {method: 'POST',body: JSON.stringify({fromPath: from.path,toPath: to.path,time: new Date().toISOString()})});// 3. 页面滚动到顶部window.scrollTo(0, 0);
});
四、全局守卫的执行顺序
  1. 触发路由跳转 → beforeEach(全局前置)
  2. 加载异步路由组件(若有)
  3. 执行目标路由的路由独享守卫(beforeEnter
  4. 执行目标组件内的 beforeRouteEnter 守卫
  5. 所有异步操作完成 → beforeResolve(全局解析)
  6. 导航确认,组件渲染 → afterEach(全局后置)
五、核心使用场景
  • beforeEach:权限验证、登录拦截、动态路由生成。
  • beforeResolve:路由跳转前的异步数据预处理。
  • afterEach:页面访问日志、滚动位置重置、埋点统计。
六、注意事项
  1. 避免无限循环:在 beforeEach 中重定向时,需确保条件判断正确(如登录页不重定向自身)。
  2. 异步操作处理:若有异步逻辑(如接口请求),需用 async/await 包裹,并在完成后调用 next()
  3. 性能影响:全局守卫会拦截所有路由跳转,复杂逻辑可能影响性能,建议保持简洁。

全局守卫是 Vue Router 中实现统一导航控制的核心工具,通过合理组合三类守卫,可实现从权限验证到数据处理的全流程管控。


2.2路由独享守卫

可以为某个特定的路由配置守卫,只对该路由生效。

  • beforeEnter
    • 触发时机:在进入对应的路由之前触发。
    • 参数:接收三个参数,分别是to(即将要进入的目标路由对象)、from(当前导航正要离开的路由对象)、next(和全局守卫中的next 函数作用相同)。
    • 示例
const router = new VueRouter({routes: [{path: '/admin',component: Admin,beforeEnter: (to, from, next) => {// 只有管理员角色才能访问const userRole = localStorage.getItem('role'); if (userRole === 'admin') {next();} else {next('/forbidden'); // 无权限则重定向到禁止访问页面}}}]
})

在 Vue Router 中,路由独享守卫是一种仅作用于特定路由配置的导航钩子,允许你在某个路由跳转前进行定制化拦截和处理,而不必影响其他路由。以下是其核心用法与场景:

一、核心语法(beforeEnter
const router = new VueRouter({routes: [{path: '/admin',component: AdminPanel,beforeEnter: (to, from, next) => {// 路由独享守卫逻辑if (!isAdmin) {next('/login'); // 无权限则重定向} else {next(); // 允许访问}}}]
});
二、参数与执行流程
1. 参数
  • to:目标路由对象(包含路径、参数、元信息等)。
  • from:当前路由对象。
  • next:控制导航行为的函数(同全局守卫的 next)。
2. 执行时机
  • 在全局前置守卫(beforeEach)之后,组件内守卫(beforeRouteEnter)之前执行。
  • 仅在进入该路由时触发,离开时不触发。
三、典型应用场景
1. 权限控制(如管理员页面)
{path: '/admin',component: AdminPanel,beforeEnter: (to, from, next) => {const userRole = localStorage.getItem('role');if (userRole === 'admin') {next(); // 管理员允许访问} else {next('/forbidden'); // 非管理员跳转至禁止页}}
}
2. 数据预处理
{path: '/profile/:id',component: UserProfile,beforeEnter: async (to, from, next) => {try {// 预加载用户数据const user = await fetchUser(to.params.id);// 将数据存入路由元信息,供组件使用to.meta.user = user;next();} catch (error) {next('/404'); // 加载失败跳转 404}}
}
3. 导航条件判断
{path: '/payment',component: PaymentPage,beforeEnter: (to, from, next) => {// 检查购物车是否有商品const hasItems = localStorage.getItem('cartItems');if (hasItems) {next();} else {next('/cart'); // 无商品则跳转购物车}}
}
四、与其他守卫的对比
守卫类型作用范围触发时机适用场景
全局前置守卫所有路由路由跳转前统一权限验证、登录拦截
路由独享守卫单个路由配置进入特定路由前特定页面的权限控制、数据预加载
组件内守卫组件内部组件实例相关的导航阶段组件级别的导航逻辑
五、注意事项
  1. 只作用于直接匹配的路由
    如果路由配置了子路由,beforeEnter 仅在进入该路由时触发,不会作用于子路由。

  2. 避免重复逻辑
    若多个路由需要相同的守卫逻辑,建议使用全局守卫或高阶函数封装,减少代码冗余。

  3. 异步操作处理
    若守卫中包含异步请求(如验证 Token),需使用 async/await 确保数据加载完成后再调用 next()

六、总结

路由独享守卫是 Vue Router 中实现细粒度导航控制的灵活工具,适合在不影响全局导航的前提下,对特定路由添加定制化的拦截逻辑。合理使用它可提升代码的可维护性,避免全局守卫过于臃肿。


2.3组件内守卫

在路由组件内部定义的守卫,只在当前组件对应的路由跳转时生效。

  • beforeRouteEnter
    • 触发时机:在路由进入该组件之前触发,此时组件实例还未被创建,所以不能访问this
    • 参数:接收三个参数,分别是to(即将要进入的目标路由对象)、from(当前导航正要离开的路由对象)、nextnext 函数可以接收一个回调函数,在组件实例创建好之后执行 )。
    • 示例
export default {beforeRouteEnter(to, from, next) {// 模拟获取数据后再进入组件getData().then(data => {next(vm => {vm.$data.data = data; // vm 是组件实例});}).catch(() => {next(false);});}
}
  • beforeRouteUpdate
    • 触发时机:在当前路由改变,但是该组件被复用时调用,比如在带有动态参数的路由中,当参数变化时,组件会被复用,此时会触发该守卫。
    • 参数:接收三个参数,分别是to(即将要进入的目标路由对象)、from(当前导航正要离开的路由对象)、next(和其他守卫中的next 函数作用相同)。
    • 示例
export default {beforeRouteUpdate(to, from, next) {// 当路由参数变化时,重新获取数据if (to.params.id!== from.params.id) {this.fetchNewData(to.params.id);}next();}
}
  • beforeRouteLeave
    • 触发时机:在导航离开该组件时触发,可用于询问用户是否确认离开,比如用户在表单中输入了内容还未保存时。
    • 参数:接收三个参数,分别是to(即将要进入的目标路由对象)、from(当前导航正要离开的路由对象)、next(和其他守卫中的next 函数作用相同)。
    • 示例
export default {beforeRouteLeave(to, from, next) {if (this.hasUnsavedChanges) {const confirmLeave = window.confirm('你有未保存的更改,确定要离开吗?');if (confirmLeave) {next();} else {next(false);}} else {next();}}
}

通过合理运用这些路由守卫,可以实现丰富且强大的导航控制逻辑,提升应用的安全性和用户体验。

在 Vue Router 中,组件内守卫是直接定义在路由组件内部的导航钩子,用于控制该组件实例相关的路由导航行为。与全局守卫和路由独享守卫不同,组件内守卫仅作用于当前组件,提供更精细的导航控制。以下是其核心用法与场景:

一、三种组件内守卫
1. beforeRouteEnter
  • 触发时机:在路由进入组件前触发,此时组件实例尚未创建,因此无法访问 this
  • 用途:可通过 next 回调访问组件实例,常用于在路由进入前预加载数据。
  • 示例
    export default {beforeRouteEnter(to, from, next) {// 异步获取数据(如用户信息)fetchUser(to.params.id).then(user => {// 通过 next 回调访问组件实例next(vm => {vm.user = user; // 将数据传递给组件实例});});}
    }
    
2. beforeRouteUpdate
  • 触发时机:在当前路由改变(如参数变化)但组件被复用时触发,此时组件实例已存在,可访问 this
  • 用途:常用于动态参数路由(如 /user/:id)的更新逻辑,避免组件重复创建。
  • 示例
    export default {watch: {// 传统方式:监听 $route 变化$route(to) {this.fetchData(to.params.id);}},// 更优解:使用组件内守卫beforeRouteUpdate(to, from, next) {// 参数变化时重新加载数据if (to.params.id !== from.params.id) {this.fetchData(to.params.id);}next();}
    }
    
3. beforeRouteLeave
  • 触发时机:在导航离开当前组件时触发,可访问 this
  • 用途:常用于阻止用户意外离开(如未保存表单),或清理资源。
  • 示例
    export default {data() {return {formDirty: false // 表单是否已修改};},beforeRouteLeave(to, from, next) {if (this.formDirty) {const confirmLeave = window.confirm('表单尚未保存,确定离开?');confirmLeave ? next() : next(false); // 确认后允许离开} else {next(); // 未修改直接放行}}
    }
    
二、组件内守卫的执行顺序

当路由发生变化时,守卫的触发顺序为:

  1. 全局beforeEach
  2. 路由独享beforeEnter
  3. 组件内
    • 当前组件的 beforeRouteLeave(若离开当前组件)
    • 目标组件的 beforeRouteEnter(若进入新组件)
  4. 全局beforeResolve
  5. 全局afterEach
三、典型应用场景
1. 数据预加载
export default {beforeRouteEnter(to, from, next) {// 进入组件前预加载文章数据fetchArticle(to.params.id).then(article => {next(vm => {vm.article = article;});});}
}
2. 动态路由参数更新
export default {beforeRouteUpdate(to, from, next) {// 当路由参数变化时(如从 /user/1 到 /user/2)this.fetchUser(to.params.id);next();}
}
3. 防止数据丢失
export default {beforeRouteLeave(to, from, next) {// 检查是否有未保存的草稿if (this.hasDraft) {saveDraft().then(() => next());} else {next();}}
}
四、与其他守卫的对比
守卫类型定义位置能否访问 this适用场景
全局守卫路由配置文件全局权限验证、日志记录
路由独享守卫路由配置对象特定路由的权限控制
组件内守卫组件内部beforeRouteEnter 不可,其他可组件级的导航逻辑、数据预加载
五、注意事项
  1. beforeRouteEnter 中访问组件实例
    由于此时组件尚未创建,需通过 next(vm => { ... }) 回调访问实例。

  2. 避免重复逻辑
    若多个组件需要相同的守卫逻辑,可使用 mixin 或全局守卫减少代码冗余。

  3. 异步操作处理
    若守卫中包含异步请求(如验证 Token),需确保数据加载完成后再调用 next()

六、总结

组件内守卫是 Vue Router 中实现组件级导航控制的强大工具,通过 beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave 三个钩子,可精确控制组件实例的导航生命周期。合理使用组件内守卫能提升用户体验(如防止数据丢失),并优化组件性能(如复用组件时的数据更新)。


3.history模式与hash模式

在 Vue Router 中,history 模式和**hash 模式**是两种不同的路由实现方式,主要区别在于 URL 的表现形式和浏览器历史记录的处理方式。以下是详细对比与选择建议:

在这里插入图片描述

一、核心区别
特性hash 模式(默认)history 模式
URL 格式http://example.com/#/homehttp://example.com/home
路径标识符使用 # 符号分隔路径(如 #/user/1直接使用真实路径(如 /user/1
历史记录hash 变化会触发浏览器历史记录,但不会向服务器发送请求依赖 HTML5 History API(pushState/replaceState),路径变化会被记录到历史中
服务器配置无需特殊配置,所有请求都指向根页面需要服务器配置,确保所有路由请求都返回同一个 HTML 文件
兼容性支持所有浏览器(包括 IE9+)依赖 HTML5 History API,IE9 及以下不支持
二、hash 模式详解
  1. 工作原理
  • URL 中的 # 及其后的内容被视为浏览器的 hash 值,不会被发送到服务器。
  • hash 变化时(如 #/home#/about),Vue Router 会拦截并根据 hash 值渲染对应组件。
  1. 优点
  • 无需服务器配置:所有请求都指向根页面(如 index.html),适合快速开发和静态网站。
  • 兼容性强:支持所有现代浏览器,甚至包括 IE9。
  1. 缺点
  • URL 不美观# 符号在 URL 中较为突兀,不符合传统 URL 格式。
  • SEO 不友好:搜索引擎爬虫通常会忽略 hash 值,不利于页面收录。
三、history 模式详解
  1. 工作原理
  • 使用 HTML5 的 pushStatereplaceState API 操作浏览器历史记录,URL 看起来像传统的静态页面路径(如 /home)。
  • 当用户访问 /user/1 时,浏览器会向服务器发送请求,但实际上所有路径都应返回同一个 HTML 文件(如 index.html),由 Vue Router 在客户端处理路由逻辑。
  1. 优点
  • URL 更优雅:没有 # 符号,符合传统 URL 格式,提升用户体验。
  • SEO 友好:搜索引擎可以直接抓取真实路径,有利于页面收录。
  1. 缺点
  • 服务器配置复杂:需要服务器配置所有路由请求都返回 index.html,否则会出现 404 错误(见下方服务器配置示例)。
  • 兼容性较差:不支持 IE9 及以下浏览器。
四、服务器配置示例(history 模式)
  1. Node.js (Express)
const express = require('express');
const app = express();// 静态文件处理
app.use(express.static(__dirname + '/dist'));// 所有路由请求都返回 index.html
app.get('*', function(req, res) {res.sendFile(__dirname + '/dist/index.html');
});app.listen(8080);
五、如何选择?
  • 优先使用 history 模式
    如果项目需要良好的 SEO、更优雅的 URL,且不考虑 IE9 及以下浏览器,推荐使用 history 模式。

  • 使用 hash 模式的场景

    • 项目不需要 SEO(如内部管理系统)。
    • 无法配置服务器(如 GitHub Pages、静态网站托管)。
    • 需要兼容 IE9 及以下浏览器。
六、切换模式的方法

在 Vue Router 配置中,通过 mode 选项指定模式:

const router = new VueRouter({mode: 'history',  // 启用 history 模式(默认是 hash 模式)routes: [...]
});
七、总结
场景hash 模式history 模式
静态网站/快速开发❌(需服务器配置)
企业内部系统✅(兼容性好)✅(URL 更优雅)
电商/内容网站(需 SEO)
兼容性要求✅(支持 IE9+)❌(不支持 IE9 及以下)

选择时需权衡 URL 美观性、SEO 需求、服务器配置复杂度和浏览器兼容性。history 模式是现代 Web 应用的首选,但需要服务器配合;hash 模式则适用于快速迭代和兼容性要求高的场景。


(三)、vue-router(路由管理)

vue的一个插件库,专门用来实现SPA应用

1.安装与配置

使用npm install vue-router@3安装,然后在项目中进行配置。
使用:Vue.use(Router);

// router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';Vue.use(Router);export default new Router({// 路由模式,可选'hash'(默认,URL中包含#)和'history'(更美观的URL)mode: 'history', routes: [{// 路由路径path: '/', // 路由名称name: 'Home', // 对应的组件component: Home },{path: '/about',name: 'About',component: About}]
});

main.js中引入并使用路由:

import Vue from 'vue';
import App from './App.vue';
import router from './router';new Vue({router,render: h => h(App)
}).$mount('#app');

2.路由导航与参数

  1. 导航:使用<router-link>组件进行路由导航。
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
  1. 动态路由参数:在路由路径中使用参数,如/user/:id,可以在组件中通过$route.params获取参数值。
// User.vue
export default {created() {const userId = this.$route.params.id;console.log('用户ID:', userId);}
};

(四)对SPA应用的理解

  1. 定义:单页 Web 应用(single page web application,SPA )
  2. 页面特征:整个应用只有一个完整的页面
  3. 交互特点:点击页面中的导航链接不会刷新页面,只会做页面的局部更新
  4. 数据获取:数据需要通过 ajax 请求获取

(五)基本路由

注意:

  1. 存储位置
    • 路由组件:通常存放在 pages 文件夹
    • 一般组件:通常存放在 components 文件夹
  2. 路由组件销毁与挂载:通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载
  3. 组件路由信息属性:每个组件都有自己的 $route 属性,里面存储着自己的路由信息
  4. 全局路由实例获取:整个应用只有一个 router,可以通过组件的 $router 属性获取到 。

路由传参

query参数(静态)

在这里插入图片描述
在这里插入图片描述

命名路由
一、命名路由的作用

简化路由跳转:无需硬编码完整路径,通过路由名称(name)实现跳转,避免路径变更时大量修改代码。

二、使用步骤
1. 给路由“命名”(配置阶段)

在路由配置中,为目标路由添加 name 属性:

const routes = [{path: '/demo',component: Demo,children: [{path: 'test',component: Test,children: [{name: 'hello', // 给路由命名(关键)path: 'welcome',component: Hello}]}]}
]
2. 简化跳转(组件中使用)

未简化前:需写完整路径,易出错且难维护:

<router-link to="/demo/test/welcome">跳转</router-link>

简化后:通过 name 跳转,路径变化时只需改配置:

<router-link :to="{ name: 'hello' }">跳转</router-link>

简化写法:命名路由 + query 参数

<!-- 简化写法:命名路由 + query 参数 -->
<router-link :to="{ name: 'hello', // 路由名称(对应路由配置的 name: 'hello')query: {       // 传递 query 参数(会显示在 URL 中,如 ?id=666&title=你好)id: 666, title: '你好' } }"
>跳转并传参
</router-link>
三、核心优势
  • 解耦路径与跳转:路由名称不变时,即使路径(如 /demo/test/welcome)修改,跳转代码无需改动。
  • 支持动态参数:结合 params/query 传参更灵活(如 :to="{ name: 'hello', params: { id: 1 } }" )。
总结

命名路由是给路由起一个“别名”(name),让跳转从“写死路径”变成“调用名称”,核心价值是简化跳转逻辑、提升可维护性

路由的params参数(动态)
1.配置路由,声明接收 params 参数

配置路由以接收 params 参数,通过 占位符(:id:title 定义动态路径,让组件能接收 URL
中的动态参数。

1.1. 路由配置(核心片段)
{path: '/home',component: Home,children: [{component: Message,children: [{name: 'xiangqing', path: 'detail/:id/:title', // 占位符声明 params 参数component: Detail}]}]
}

代码解析:

  • path: 'detail/:id/:title'
    • :id:title 占位符,声明该路由需要接收 idtitle 两个 params 参数。
    • 访问时路径如 /home/message/detail/1/xxx,其中 1xxx 会作为 params 传递。

流程说明 :

  1. 路由定义
    通过 path: 'detail/:id/:title' 告诉 Vue Router:

    • 该路径是动态的,idtitle 是可变参数。
    • 这些参数会以 params 形式传递给 Detail 组件。
  2. 参数传递与接收

    • 跳转时需通过 params 传入数据(如 this.$router.push({ name: 'xiangqing', params: { id: 1, title: 'xxx' } }) )。
    • Detail 组件中通过 this.$route.params.idthis.$route.params.title 接收参数。

核心特点

  • 动态路径:URL 中的 idtitle 是动态的,不同参数对应不同页面状态。
  • 强关联路由params 参数必须与路由配置的占位符一一对应,否则路由无法匹配。
1.2对比 query 参数
对比项params 参数query 参数
路径形式/detail/1/xxx(参数嵌入路径)/detail?id=1&title=xxx(参数跟在 ? 后)
路由配置需用 :占位符 声明无需特殊配置
参数是否必填是(否则路由不匹配)否(可传可不传)
1.3 注意事项
  1. 参数必填性
    由于 params 参数通过占位符声明,跳转时必须传入对应参数,否则路由无法匹配(如少传 title 会导致 404)。

  2. 命名路由配合
    建议结合 name: 'xiangqing' 使用,跳转时代码更简洁:

    this.$router.push({ name: 'xiangqing', params: { id: 1, title: 'xxx' } 
    })
    
  3. 组件接收参数
    Detail 组件中,通过 this.$route.params 而非 props 接收(除非开启 props: true 配置)。

这是 Vue Router 中 动态路由传参 的基础用法,核心是通过 占位符 让 URL 携带动态数据,常用于商品详情、文章详情等场景~

2.params 参数的传递方式:
1. 字符串写法(直接拼接路径)
<!-- 跳转并携带 params 参数(字符串拼接路径) -->
<router-link to="/home/message/detail/666/你好">跳转</router-link>
  • 特点
    • 直接拼接 params 到 URL(666id你好title)。
    • 需严格按照路由配置的 path: 'detail/:id/:title' 格式拼接,易出错。
2. 对象写法(推荐)
<!-- 跳转并携带 params 参数(对象写法) -->
<router-link :to="{ name: 'xiangqing', params: { id: 666, title: '你好' } }"
>跳转
</router-link>
  • 关键规则
    • 必须用 name: 'xiangqing'(路由的命名),不能用 path
    • 通过 params 字段传递参数,Vue Router 会自动拼接成动态路径。
注意事项

对象写法的强制规则

  • 当用对象传递 params 时,必须通过 name 匹配路由,而不能用 path
  • 原因:path 是静态的,无法动态拼接 paramsname 与路由配置的 name: 'xiangqing' 关联,能正确解析 params
两种写法对比
写法优点缺点适用场景
字符串写法简单直观易因路径变化(如参数顺序)出错简单场景,参数少且固定
对象写法解耦路径与参数,更健壮需定义路由 name复杂场景,参数多或动态变化
核心结论

传递 params 参数时:

  • 若用 对象写法,必须配合 name(不能用 path),这是 Vue Router 的强制规则。
  • 推荐优先用 对象写法,避免路径拼接错误,且更易维护(路由名称不变时,路径变化不影响跳转)。

这是 Vue Router 中 params 参数传递的核心细节,记住 “对象写法必须用 name” 即可避免常见错误~

3. 接收 params 参数:

在组件中获取路由传递的 params 参数(如 idtitle),用于渲染动态内容(如商品详情、文章标题)。

1.关键代码
// 组件中接收 params 参数
const id = this.$route.params.id
const title = this.$route.params.title
2.流程说明
  1. 路由传递 params
    通过 router-linkthis.$router.push 传递 params(如 { params: { id: 666, title: '你好' } } )。

  2. 组件接收参数
    Vue Router 会将 params 挂载到 this.$route.params 中,组件直接访问 this.$route.params.idthis.$route.params.title 即可。

3.与 query 参数的区别
参数类型存储位置组件中获取方式特点
params动态路径(如 /detail/666/你好this.$route.params.xxx参数隐藏在路径中,更“干净”
queryURL 查询字符串(如 ?id=666this.$route.query.xxx参数显示在 URL 中,可分享
4.注意事项
  1. 路由配置依赖
    必须在路由中通过 path: 'detail/:id/:title' 声明 params 占位符,否则 this.$route.params 无法获取参数。

  2. 组件更新问题
    如果组件复用(如不同 id 但同一路由),需通过 watch 监听 $route.params 变化:

    watch: {'$route.params'() {// 参数变化时重新加载数据this.fetchData(this.$route.params.id);}
    }
    
5.总结

接收 params 参数的核心是通过 this.$route.params.xxx,需注意路由配置的占位符声明,以及组件复用场景下的参数监听。这是 Vue Router 动态路由传参的基础用法,常用于商品详情、文章详情等场景。


路由的props配置

在 Vue Router 中,props 配置是一种将路由参数(如 paramsquery)直接映射为组件 props 的机制,目的是解耦组件与路由,让组件更易于测试和复用。以下是其核心用法与场景:

一、基础用法(三种模式)
1. 布尔模式(最常用)
  • 配置props: true
  • 效果:将 params 参数转为组件 propsquery 不处理。
  • 示例
    // 路由配置
    {path: '/user/:id',component: User,props: true // 开启 props 模式
    }// User 组件
    export default {props: ['id'], // 直接接收路由 params 参数mounted() {console.log(this.id); // 访问路由参数}
    }
    
2. 对象模式
  • 配置props: { key: value }
  • 效果:传递固定的静态数据给组件,不依赖路由参数。
  • 示例
    {path: '/about',component: About,props: { title: '关于我们', version: '1.0.0' } // 传递静态数据
    }
    
3. 函数模式(最灵活)
  • 配置props: (route) => ({...})
  • 效果:通过函数动态生成 props,可处理 paramsquery 或其他逻辑。
  • 示例
    {path: '/search',component: Search,props: (route) => ({keyword: route.query.q, // 从 query 获取参数page: parseInt(route.query.page) || 1 // 处理默认值})
    }
    

汇总:

{name:'xiangqing',path:'detail/:id',component:Detail,//第一种写法:props值为对象,该对象中所有的key - value的组合最终都会通过props传给Detail组件// props:{a:900}//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件// props:true//第三种写法:props值为函数,该函数返回的对象中每一组key - value都会通过props传给Detail组件props(route){return {id:route.query.id,title:route.query.title}
二、核心优势
  1. 组件复用性提升
    组件不再依赖 this.$route,可独立使用(如在非路由场景下复用)。

    // 无 props 配置时,组件依赖路由
    console.log(this.$route.params.id); // 耦合路由// 有 props 配置时,组件只关心 props
    console.log(this.id); // 解耦路由,可独立测试
    
  2. 测试更简单
    测试组件时,可直接传入 props,无需模拟路由环境。

    // 测试代码示例
    const wrapper = shallowMount(User, {propsData: { id: '123' } // 直接传入 props
    });
    
  3. 代码更清晰
    组件 props 声明明确,一眼看出依赖哪些参数。

三、对比直接访问 $route
方式优点缺点适用场景
直接用 $route简单直接,无需额外配置组件与路由强耦合小型项目、快速开发
props 配置解耦路由,组件可复用需要额外配置中大型项目、组件复用多
四、注意事项
  1. 仅处理 params
    props: true 时,只有 params 参数会被转为 propsquery 参数需通过函数模式手动处理。

  2. 与命名路由配合
    传递 params 时,建议用命名路由(如 name: 'user'),避免路径拼接错误。

    <router-link :to="{ name: 'user', params: { id: 1 } }">用户详情</router-link>
    
  3. 函数模式的性能
    函数模式每次路由变化都会执行,避免在函数中做复杂计算,可通过 computed 缓存结果。

五、典型场景
  • 商品详情页:通过 id 获取商品数据。

    {path: '/product/:id',component: ProductDetail,props: true
    }
    
  • 搜索结果页:通过 query 参数获取搜索关键词。

    {path: '/search',component: SearchResult,props: (route) => ({ keyword: route.query.q })
    }
    
  • 静态页面:传递固定数据(如标题、配置)。

    {path: '/help',component: HelpPage,props: { title: '帮助中心' }
    }
    
总结

props 配置是 Vue Router 中解耦组件与路由的关键机制,通过三种模式(布尔、对象、函数)将路由参数转为组件 props,让组件更独立、可测试、易复用。建议在中大型项目中优先使用,提升代码质量。

router-link的replace属性

在 Vue Router 中,router-link 是用于生成导航链接的组件,它的 replace 属性主要用于控制导航行为,以下是关于它的详细介绍:
以下是提取的文字内容:

<router-link>replace属性

  1. 作用:控制路由跳转时操作浏览器历史记录的模式
  2. 浏览器的历史记录有两种写入方式:分别为pushreplacepush是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
  3. 如何开启replace模式:<router-link replace ……>News</router-link>
1. 基本作用

replace 属性的作用是用新的历史记录条目替换当前的历史记录条目,而不是向历史记录栈中添加一个新条目。

在普通情况下,当我们使用 <router-link> 进行页面跳转时,每次跳转都会在浏览器的历史记录中新增一条记录,用户可以通过点击浏览器的“后退”按钮回到上一个页面。但是当给 <router-link> 添加了 replace 属性后,跳转时会替换当前的历史记录,此时浏览器的“后退”按钮将无法退回到跳转前的页面 。

2. 使用方式

<router-link> 组件中,直接添加 replace 属性即可,它不需要绑定具体的值,类似于 HTML 中的布尔属性,只要存在该属性,就会生效。示例代码如下:

<template><div><!-- 普通的路由链接,会增加历史记录 --><router-link to="/home">前往首页</router-link> <!-- 使用了replace属性的路由链接,会替换历史记录 --><router-link to="/about" replace>前往关于页面</router-link> </div>
</template>

上述代码中,点击“前往首页”的链接时,浏览器历史记录会新增一条记录;而点击“前往关于页面”的链接时,当前的历史记录会被替换。

3. 应用场景
  • 防止用户返回:在一些场景下,比如用户进行了不可逆的操作(如提交表单、支付成功后),不希望用户通过点击“后退”按钮回到之前的页面,此时可以使用 replace 属性。例如,在电商网站中,当用户完成支付后跳转到支付成功页面,为了避免用户误点“后退”按钮回到支付页面造成混乱,可以在支付成功页面的跳转链接中添加 replace 属性。
<router-link to="/payment-success" replace>支付成功</router-link>
  • 简化历史记录:当页面的导航逻辑比较复杂,且某些跳转不需要用户回溯时,使用 replace 属性可以让浏览器的历史记录更加简洁明了,避免历史记录中出现过多不必要的条目 。
4. 与编程式导航的对比

除了通过 <router-link>replace 属性控制导航行为外,编程式导航(this.$router.pushthis.$router.replace)也能实现类似功能。

  • this.$router.push:向历史记录栈中添加一个新条目,与普通的 <router-link> 效果类似。
  • this.$router.replace:用新的条目替换当前历史记录条目,类似于 <router-link> 加上 replace 属性。

示例代码:

export default {methods: {goToPage() {// 普通push,增加历史记录this.$router.push('/some-page'); // 使用replace,替换历史记录this.$router.replace('/another-page'); }}
}

总之,router-linkreplace 属性为我们在 Vue Router 中控制导航的历史记录行为提供了一种便捷的方式,合理使用它可以优化用户体验和页面导航逻辑。

编程式路由导航

在 Vue Router 中,除了使用 <router-link> 声明式创建导航链接外,还可以通过 编程式路由导航 实现更灵活的路由跳转。这种方式通过 JavaScript 代码触发路由变化,适用于条件跳转、事件回调等场景。

在这里插入图片描述

一、核心 API
1. this.$router.push(location)
  • 作用:向历史记录栈中添加一个新条目,等同于 <router-link to>
  • 参数:可以是字符串路径或描述目标位置的对象。
  • 示例
    // 字符串路径
    this.$router.push('/home');// 对象路径(命名路由 + params)
    this.$router.push({ name: 'user', params: { id: 123 } 
    });// 对象路径(带 query 参数)
    this.$router.push({ path: '/search', query: { keyword: 'vue' } 
    });
    
2. this.$router.replace(location)
  • 作用:替换当前历史记录条目,不创建新条目,等同于 <router-link replace>
  • 示例
    // 替换当前路由,禁止返回上一页
    this.$router.replace('/login');
    
3. this.$router.go(n)
  • 作用:在历史记录中前进或后退,参数 n 为步数。
  • 示例
    this.$router.go(1); // 前进一页(等同于 history.forward())
    this.$router.go(-1); // 后退一页(等同于 history.back())
    this.$router.go(3); // 前进三页
    
二、与 <router-link> 的对比
方式适用场景特点
<router-link>静态导航链接(如导航栏、菜单)声明式,简单直观
编程式路由导航动态逻辑跳转(如按钮点击、条件判断)灵活,可结合业务逻辑,支持异步操作
三、典型场景
1. 按钮点击跳转
<template><button @click="handleLogin">登录</button>
</template><script>
export default {methods: {handleLogin() {// 登录逻辑...this.$router.push('/dashboard');}}
}
</script>
2. 条件跳转
// 根据用户权限跳转
if (this.isAdmin) {this.$router.push('/admin');
} else {this.$router.push('/user');
}
3. 异步操作后跳转
async fetchData() {await this.api.getUser();this.$router.replace('/profile'); // 替换路由,禁止返回
}
4. 带参数跳转
// 传递 params 参数
this.$router.push({ name: 'product', params: { id: this.selectedId } 
});// 传递 query 参数
this.$router.push({ path: '/search', query: { page: 2 } 
});
四、注意事项
  1. 路由钩子与导航守卫
    编程式导航同样会触发全局导航守卫(如 beforeEach)和路由独享守卫(如 beforeEnter),需注意逻辑顺序。

  2. 命名路由优先
    传递动态参数(如 params)时,建议使用命名路由,避免路径拼接错误。

  3. 错误处理
    导航失败(如路由不存在)会返回一个被拒绝的 Promise,可以通过 .catch 捕获错误:

    this.$router.push('/non-existent').catch(err => {console.error('导航失败:', err);
    });
    
五、总结

编程式路由导航是 Vue Router 提供的 JavaScript 方式控制路由跳转 的能力,通过 pushreplacego 等方法实现灵活的导航逻辑,适用于需要动态控制路由的场景。与 <router-link> 结合使用,能满足各种复杂的路由需求。

缓存路由组件

在 Vue Router 中,缓存路由组件 是提升单页应用性能和用户体验的重要手段,主要通过 <keep-alive> 组件实现。以下是核心机制与使用场景:

在这里插入图片描述

一、核心原理
  • 普通组件行为:组件在切换时会被销毁(beforeDestroy/destroyed),再次进入时重新创建(created/mounted)。
  • 缓存组件行为:使用 <keep-alive> 包裹的组件,在切换时不会被销毁,而是进入“缓存状态”(deactivated),再次进入时直接恢复(activated),避免重复渲染和数据请求。
二、基础用法(✔️)
1. 全局缓存所有路由组件
<!-- App.vue -->
<router-view v-slot="{ Component }"><keep-alive><component :is="Component" /></keep-alive>
</router-view>
2. 缓存特定组件(推荐)

通过 include/exclude 指定缓存组件名称(组件的 name 选项):

<!-- 只缓存 Home 和 User 组件 -->
<keep-alive include="Home,User">//include:组件名<router-view />
</keep-alive><!-- 排除 Login 组件 -->
<keep-alive exclude="Login"><router-view />
</keep-alive>
3. 动态缓存(通过路由元信息)

在路由配置中添加 meta.keepAlive,动态控制是否缓存:

// router.js
const routes = [{path: '/home',component: Home,meta: { keepAlive: true } // 需要缓存},{path: '/detail',component: Detail,meta: { keepAlive: false } // 不需要缓存}
];
<!-- App.vue -->
<router-view v-slot="{ Component }"><keep-alive><component :is="Component" v-if="$route.meta.keepAlive" /></keep-alive><component :is="Component" v-if="!$route.meta.keepAlive" />
</router-view>
语法与作用说明

在 Vue 中,<keep-alive> 组件的 include 属性用于指定需要缓存的组件名称,值可以是字符串、正则表达式,也可以是数组(数组里放组件名称字符串) 。你代码里的写法:

<keep-alive :include="['News','Message']">  
<router-view></router-view> </keep-alive>

表示:仅缓存名称为 NewsMessage 的组件,当这两个组件在 <router-view>
中切换时,会被缓存(组件实例不会销毁,再次进入时不会重新执行创建阶段的钩子,而是触发 activated 等缓存相关钩子 ),其他未匹配名称的组件则不会被缓存。

关键前提条件

  1. 组件需有 name 选项NewsMessage 组件必须在自身定义中显式声明 name,且名称要和 include 里的字符串严格一致,
    示例:
// News.vue export default
{   name: 'News', // 必须声明,且和 include 里的 'News' 一致   // ... }// Message.vue export default {   name: 'Message',    // ... }

如果是单文件组件未手动写 name,Vue 会默认将文件名作为 name(比如 News.vue 会默认 name: 'News' ),但为了清晰和避免意外,建议手动声明。

  1. 配合路由使用场景: 这种写法通常用于在路由切换时,缓存特定的页面级组件(即通过 router-view 渲染的组件 )。比如 NewsMessage 是两个路由组件,通过路由配置映射到不同路径,当在这两个路由间切换时,就能利用
    keep-alive 缓存它们的状态。

常见扩展用法对比

  • 字符串形式include="News" ,只能缓存一个组件,适合单一目标场景。
  • 正则形式:include="/News|Message/"(需结合 v-bind 绑定,因为是 JavaScript 表达式 ),用正则匹配组件名称,灵活但相对难维护。
  • 数组形式(你代码里的写法)::include="['News','Message']" ,清晰列出要缓存的组件,适合明确知道缓存范围的场景,也是实际项目里常用的方式。

只要满足上述组件 name 匹配等条件,你的写法是合法且推荐的,能精准控制缓存范围,避免不必要的组件缓存,节省内存、提升性能。

核心区别:静态字符串 vs 动态绑定数组
写法语法类型解析方式
include="Home,User,Product"静态字符串Vue 会直接将字符串按逗号分割为数组 ['Home', 'User', 'Product']
:include="['Home','User']"动态绑定 JavaScript 数组通过 v-bind 绑定 JS 表达式,需在 Vue 实例中定义或直接写数组字面量
三、缓存组件的生命周期钩子
  • activated:组件被激活时触发(首次加载或从缓存中恢复)。
  • deactivated:组件被缓存时触发(离开但不销毁)。

典型应用:在 activated 中判断是否需要重新加载数据:

export default {data() {return {data: null,loaded: false};},activated() {if (!this.loaded) {this.fetchData(); // 只在首次加载或数据过期时请求this.loaded = true;}},methods: {fetchData() {// API 请求...}}
};
四、适用场景
  1. 频繁切换的页面:如标签页(Tab),避免每次切换都重新渲染。
  2. 数据加载耗时的页面:如商品详情页,缓存后二次访问无需重新请求数据。
  3. 需要保存状态的表单:如多步骤表单,切换步骤时保留已填写内容。
五、注意事项
  1. 内存占用:过多缓存组件会增加内存开销,建议仅缓存关键页面。
  2. 数据更新:缓存组件不会触发 mounted,需在 activated 中处理数据更新。
  3. 组件复用问题:动态路由(如 /user/:id)切换不同参数时,组件会复用而不触发 activated,需通过 watch 监听 $route 变化:
    watch: {$route() {this.fetchData(); // 路由参数变化时重新加载}
    }
    
六、高级用法
1. 结合 max 属性限制缓存数量
<keep-alive max="3"> <!-- 最多缓存 3 个组件 --><router-view />
</keep-alive>
2. 动态控制缓存状态

通过修改路由元信息或组件 name,在运行时动态决定是否缓存:

// 导航守卫中动态设置
router.beforeEach((to, from, next) => {if (to.name === 'Detail' && from.name === 'List') {to.meta.keepAlive = true; // 从列表页进入详情页时缓存}next();
});
七、总结

缓存路由组件是优化 SPA 性能的重要手段,通过 <keep-alive> 实现组件复用,避免重复渲染和数据请求。合理使用 include/exclude、路由元信息及生命周期钩子,能在提升体验的同时避免内存问题。

案例

以下是关于 Vue Router 核心特性的综合解析,通过 电商商品详情页 案例串联所有知识点:

案例场景

假设你正在开发一个电商网站,需要实现以下功能:

  • 从商品列表页点击商品,跳转到详情页(携带商品 ID)。
  • 详情页包含 基本信息用户评价相关推荐 三个子页面(嵌套路由)。
  • 评价页支持按时间/评分筛选(query 参数)。
  • 商品详情页需要缓存,避免重复加载数据。
1. 路由配置(router.js
const routes = [// 商品列表页{ path: '/products', component: ProductsList },// 商品详情页(动态路由 + 嵌套路由){path: '/product/:id', // params 参数:商品 IDname: 'ProductDetail', // 命名路由component: ProductDetail,props: true, // 启用 props 接收 paramschildren: [{ path: '', redirect: 'info' }, // 默认子路由{ path: 'info', component: ProductInfo },{ path: 'reviews', component: ProductReviews },{ path: 'related', component: RelatedProducts }]}
];
2. 路由传参与导航
(1)query 参数(筛选条件)
<!-- 商品评价页:筛选按钮 -->
<router-link :to="{ name: 'ProductDetail', params: { id: productId }, query: { sort: 'time' } }"
>按时间排序
</router-link><!-- 在组件中获取 query 参数 -->
export default {computed: {sortType() {return this.$route.query.sort || 'default';}}
}
(2)命名路由 + params 参数(商品 ID)
<!-- 商品列表项:跳转到详情页 -->
<router-link :to="{ name: 'ProductDetail', params: { id: item.id } }"
>{{ item.name }}
</router-link><!-- 编程式导航(按钮点击) -->
methods: {goToDetail() {this.$router.push({name: 'ProductDetail',params: { id: this.selectedId }});}
}
(3)路由的 props 配置(简化参数接收)
// 路由配置
{path: '/product/:id',component: ProductDetail,props: true // 将 params 转为组件 props
}// 在 ProductDetail 组件中直接接收
export default {props: ['id'],mounted() {this.fetchProductData(this.id);}
}
3. router-link 的 replace 属性
<!-- 使用 replace 替换当前历史记录,禁止后退 -->
<router-link :to="{ name: 'ProductDetail', params: { id } }"replace
>立即购买
</router-link>
4. 缓存路由组件(keep-alive
<!-- App.vue:缓存商品详情页 -->
<router-view v-slot="{ Component }"><keep-alive include="ProductDetail"><component :is="Component" /></keep-alive>
</router-view><!-- 被缓存组件的生命周期钩子 -->
export default {activated() {// 组件被激活时触发(缓存后首次加载或重新显示)if (!this.$route.meta.loaded) {this.fetchData(); // 只在首次加载时请求数据this.$route.meta.loaded = true;}},deactivated() {// 组件被缓存时触发(隐藏但不销毁)}
}
5. 完整流程图
商品列表页(/products)└── 点击商品(携带 id 参数)↓
商品详情页(/product/123)├── 默认显示:基本信息(/product/123/info)├── 切换到评价页(/product/123/reviews?sort=time)│     └── query 参数控制筛选逻辑└── 切换到相关推荐(/product/123/related)[缓存机制]
当从详情页跳转到其他页面时,详情页组件不会销毁,
再次返回时直接显示缓存内容,无需重新加载数据。
核心知识点总结
特性作用示例
query 参数用于传递可选参数(如筛选条件),显示在 URL 中(?sort=time)。<router-link :to="{ query: { sort: 'time' } }">
命名路由为路由定义名称,避免硬编码路径,提高可维护性。name: 'ProductDetail' + this.$router.push({ name: '...' })
params 参数用于传递必需参数(如 ID),通过动态路由(:id)接收。path: '/product/:id' + this.$route.params.id
props 配置将 params 转为组件 props,解耦组件与路由。props: true + export default { props: ['id'] }
replace 属性替换当前历史记录,禁止返回上一页。<router-link replace>
缓存路由组件使用 keep-alive 缓存组件状态,避免重复渲染。<keep-alive include="ProductDetail"> + activated() 生命周期钩子
两个新的生命周期钩子
  1. ** 作用**:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
  2. 具体名字
    1. activated 路由组件被激活时触发。
    2. deactivated 路由组件失活时触发。在这里插入图片描述

Vue UI组件库

一、移动端组件库

库名特点技术栈官网地址适用场景
Vant有赞出品,更新活跃,组件全Vue 2/3https://vant-contrib.gitee.io/vant/电商、表单、中大型项目
NutUI京东出品,轻量高效Vue 2/3https://nutui.jd.com/快速迭代项目
Cube UI滴滴开源,定制性强Vue 2https://didi.github.io/cube-ui/需深度定制的移动端项目
Mint UI经典老库(维护停滞)Vue 2https://github.com/ElemeFE/mint-ui旧项目维护(慎用于新项目)

二、PC 端组件库

库名特点技术栈官网地址适用场景
Element UI元老级,文档完善Vue 2https://element.eleme.cn/企业后台、管理系统
Element PlusElement 官方 Vue 3 版本Vue 3https://element-plus.org/新项目(Vue 3 技术栈)
View UI原 iView,设计现代Vue 2/3https://www.iviewui.com/中后台系统、数据可视化
Ant Design Vue阿里系,组件丰富Vue 2/3https://www.antdv.com/复杂业务系统、中台产品

三、跨端/全场景组件库

库名特点技术栈官网地址适用场景
Naive UI全场景,性能优异Vue 3https://www.naiveui.com/中大型 Web 应用(Vue 3)
Arco Design字节跳动出品,设计统一Vue 2/3https://arco.design/vue企业级产品、多端一致性需求

在这里插入图片描述

四、使用建议

  1. 技术栈匹配

    • Vue 2:选 Element UI、Vant、View UI
    • Vue 3:选 Element Plus、Naive UI、Ant Design Vue
  2. 场景选择

    • 电商/移动端:Vant(功能最全)
    • 企业后台:Element UI/Plus(稳定)或 Ant Design Vue(组件丰富)
    • 快速开发:NutUI(体积小)或 View UI(设计现代)
  3. 避坑指南

    • 避免在新项目中使用 Mint UI(已停止维护)
    • 注意组件库与 Vue 版本的兼容性
    • 按需引入组件以减小打包体积(参考各库文档)

五、快速上手示例(Vant)

# 安装
npm i vant@next -S  # Vue 3 项目
npm i vant -S       # Vue 2 项目# 按需引入(推荐)
npm i unplugin-vue-components unplugin-auto-import -D
// vite.config.js
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'export default defineConfig({plugins: [AutoImport({resolvers: [VantResolver()],}),Components({resolvers: [VantResolver()],}),],
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916216.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 Windows 上安装设置 MongoDB及常见问题

介绍 MongoDB 是一个开源的 NoSQL 数据库系统&#xff0c;它以一种灵活的类似 JSON 的格式&#xff08;称为 BSON&#xff08;二进制 JSON&#xff09;&#xff09;存储数据。它使用动态模式&#xff0c;这意味着与关系型数据库不同&#xff0c;MongoDB 不需要在向数据库添加数…

Effective C++ 条款01:视 C++ 为一个语言联邦

Effective C 条款01&#xff1a;视 C 为一个语言联邦核心思想&#xff1a;C 是由多个子语言组成的联邦&#xff0c;每个子语言有自己的编程范式。理解这些子语言及其规则切换&#xff0c;是写出高效 C 代码的关键。 四个子语言及其规则&#xff1a; C 语言 基础&#xff1a;过程…

云效CI/CD教程(PHP项目)

参考文档 参考云效的官方文档https://help.aliyun.com/zh/yunxiao/ 一、新建代码库 这是第一步&#xff0c;和码云的差不多 二、配SSH密钥 这个和码云&#xff0c;github上类似&#xff0c;都需要&#xff0c;云效的SSH密钥证书不是采用 RSA算法&#xff0c;而是采用了ED2…

单片机是怎么控制的

单片机作为电子系统的控制核心&#xff0c;通过接收外部信号、执行预设程序、驱动外部设备的方式实现控制功能&#xff0c;其控制过程涉及信号输入、数据处理和指令输出三个关键环节&#xff0c;每个环节的协同配合决定了整体控制效果。 信号输入&#xff1a;获取外部信息 单片…

deepseek本地部署,轻松实现编程自由

小伙伴们&#xff0c;大家好&#xff0c;今天我们来实现deepseek本地部署&#xff0c;轻松实现编程自由&#xff01;安装ollama 安装ollama 首先我们安装ollama 打开ollama官网&#xff0c;下载安装符合自己系统的版本。 找到要安装的模型deepseek-r1开始-运行 输入cmd出现…

基础NLP | 常用工具

编辑器 PycharmVSCodeSpyderPython 自带 ideVim 机器学习相关python框架 Pytorch 学术界宠儿&#xff0c;调试方便&#xff0c;目前的主流Tensorflow 大名鼎鼎&#xff0c;工程配套完善Keras 高级封装&#xff0c;简单好用&#xff0c;现已和Tensorflow合体Gensim 训练词向…

Unity3D + VR头显 × RTSP|RTMP播放器:构建沉浸式远程诊疗系统的技术实践

一、背景&#xff1a;远程医疗迈入“沉浸式协同”的新阶段 过去&#xff0c;远程医疗主要依赖视频会议系统&#xff0c;实现基础的远程问诊、会诊或术中指导。虽然初步解决了地域限制问题&#xff0c;但其单视角、平面化、缺乏沉浸感与交互性的特征&#xff0c;已无法满足临床…

海云安斩获“智能金融创新应用“标杆案例 彰显AI安全左移技术创新实力

近日&#xff0c;由中国人民银行广东省分行、广东省金融管理局、广东省政务服务和数据管理局指导&#xff0c;广东省金融科技协会主办的“智能金融 创新应用”优秀案例名单最终揭晓&#xff0c;海云安开发者安全助手系统项目凭借其创新的"AI安全左移"技术架构&#x…

Fluent许可与网络安全策略

在流体动力学模拟领域&#xff0c;Fluent软件因其卓越的性能和广泛的应用而备受用户青睐。然而&#xff0c;随着网络安全威胁的不断增加&#xff0c;确保Fluent许可的安全性和合规性变得尤为重要。本文将探讨Fluent许可与网络安全策略的关系&#xff0c;为您提供一套有效的安全…

如何借助AI工具?打赢通信设备制造的高风险之战?(案例分享)

你是否曾在项目管理中遇到过那种让人心跳加速的瞬间&#xff0c;当一项风险突然暴露出来时&#xff0c;全队似乎都屏住了呼吸&#xff1f;今天&#xff0c;我就来分享一个我亲历的项目案例&#xff0c;讲述我们如何借助具体的AI工具&#xff0c;实现从数据到决策的华丽转变&…

Web服务器(Tomcat、项目部署)

1. 简介 1.1 什么是Web服务器 Web服务器是一个应用程序&#xff08;软件&#xff09;&#xff0c;对HTTP协议的操作进行封装&#xff0c;使得程序员不必直接对协议进行操作&#xff0c;让Web开发更加便捷。主要功能是"提供网上信息浏览服务"。 Web服务器是安装在服…

list 介绍 及 底层

list的相关文档&#xff1a;list - C Reference 一、list的介绍及使用 list中的接口比较多&#xff0c;此处类似&#xff0c;只需要掌握如何正确的使用&#xff0c;然后再去深入研究背后的原理&#xff0c;已达到可扩展的能力。以下为list中一些常见的重要接口。我们库里的list…

HCIP MGRE实验

一、实验要求 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有Ip地址; 2、 R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方&#xff1b; R2与R5之间使用PPP的CHAP认证&#xff0c;R5为主认证方; R3与R5之间使用HDLC封装; 3、R2、R3构建一…

基于PyTorch的多视角二维流场切片三维流场预测模型

基于PyTorch的多视角二维流场切片三维流场预测模型 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff0c;觉得好请收藏。点击跳转到网站。 1. 引言 计算流体动力学(CFD)在工程设计和科学研究中扮演…

全新轻量化PHP网盘搜索引擎系统源码

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 全新轻量化PHP网盘搜索引擎系统源码 基于PHPMYSQL开发 一、多样筛选功能&#xff1a;网站支持5类筛选功能&#xff0c;包括默认搜索、网盘类型、文件大小、时间排序以及网盘来源&#x…

C study notes[3]

文章目录operatonsloopsreferencesoperatons the fundamental operators such as ,-,* in C language can be simply manipulated. int sum 5 3; // sum 8 int difference 10 - 4; // difference 6 int product 6 * 7; // product 42the operator / was left to in…

练习实践-基础设施-文件共享-windows和linux之间的文件共享-smb服务搭建

参考来源&#xff1a; 在线书籍-linux就该这么学-第12章 安装软件包 配置文件/etc/samba/smb.conf 运维对待配置文件的态度&#xff0c;非必要不增加 安装完毕后打开Samba服务程序的主配置文件&#xff0c;好在参数并不多&#xff0c;只有37行。其中第17&#xff5e;22行代…

常用设计模式系列(十三)—组合模式

常用设计模式系列&#xff08;十三&#xff09;—组合模式 第一节 前言 hello大家好&#xff0c;今年已经过去了一半&#xff0c;年初立下的flag&#xff0c;不知道实现了没有&#xff0c;你的flag改了多少次&#xff1f;无论自己的愿望是否完成&#xff0c;我们都应该怀揣着追…

字节码操作工具——ByteBuddy应用(3)安全检查

一、检测方法名是否符合规范1、代码&#xff08;1&#xff09;MethodLoggerAgentpackage com.example.agent;import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers;import java.lang.instrument.…

NineData 数据库 DevOps 全面支持 GaussDB,国产化管理再升级!

NineData 数据库 DevOps 平台现已全面兼容 GaussDB 全线产品&#xff08;包括 GaussDB 企业级、DWS 数据仓库、openGauss 开源版&#xff09;&#xff0c;实现一站式管理。无论 GaussDB 实例部署在哪个环境&#xff0c;企业所有开发者都可以通过 NineData 统一访问&#xff0c;…