Vue router 4 基础知识讲解

9,477次阅读
没有评论

共计 9225 个字符,预计需要花费 24 分钟才能阅读完成。

1. Vue router 4 基础

在构建现代 Web 应用时,单页应用(SPA)因其流畅的用户体验和快速的页面切换能力,成为了众多项目的首选架构。
然而,在 SPA 中,随着应用功能的日益复杂,权限控制成为了一个不可忽视的问题。如何确保不同用户只能访问其被授权的资源,是保障应用安全和数据一致性的关键。
在这个过程中,路由管理扮演着至关重要的角色。Vue Router,作为 Vue 官方提供的路由管理器,不仅能够帮助我们定义应用的页面结构和导航逻辑,还能与权限控制机制紧密结合,实现细粒度的访问控制。
Vue3 项目中,通过 Vue Router 的路由守卫功能,我们可以在用户访问某个路由之前进行权限验证。例如,我们可以利用全局前置守卫(beforeEach)来检查用户的登录状态和权限级别,从而决定是否允许用户继续访问目标页面。如果用户未登录或权限不足,我们可以重定向用户到登录页面或提示页面,确保应用的安全性。
此外,Vue Router 还支持路由元信息(meta 字段),这为我们在路由层面定义额外的信息提供了便利。通过路由元信息,我们可以为不同的路由设置不同的权限要求,并在路由守卫中根据这些信息进行权限验证。这种方式使得权限控制更加灵活和可配置。

1.1 安装

可以使用 npm 包管理器直接安装,或者在创建 Vue3 新项目时,使用 create-vue 创建一个基于 Vite 的项目,并选择加入 vue-router 选项。

npm install vue-router@4
or
npm create vue@latest

1.2 配置

安装完成后,接下来需要在项目中配置Vue Router。这通常涉及以下几个步骤:

  • 创建路由实例:首先,需要导入 Vue Router 并创建一个路由实例。在这个过程中,需要定义应用的路由配置,包括各个路由的路径(path)、组件(component)等信息。
  • 挂载路由实例:然后,需要将创建的路由实例挂载到 Vue 应用中。这通常是在创建 Vue 应用实例时,通过 createApp 函数的 .use() 方法完成的。

Vue Router 4进行路由管理时,使用 createRouter() 函数来创建并配置路由器实例。createRouter()函数替代了 Vue Router 3 中的 new VueRouter() 函数。



import { createRouter, createWebHistory } from 'vue-router'


import HomeView from './HomeView.vue'
import AboutView from './AboutView.vue'


const routes = [
  { path: '/', component: HomeView },
  { path: '/about', component: AboutView },
]


const router = createRouter({
  history: createWebHistory(),
  routes,
})
export default router


import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')



template>
  RouterView>/RouterView>
/template>
script setup>
import { RouterView } from 'vue-router'
/script>

1.3 基本属性

  • path:路由路径,字符串。应该以 / 开头,除非该路由为另一条路由的子路由。当浏览器的 URL 与这个路径匹配时,就会渲染对应的组件。
  • name:路由名称,字符串,必须唯一。命名路由可以在编程式导航中通过名称来引用路由,而不是通过路径字符串。
  • component:路由组件(通常是导入的组件)。这个组件会在路由匹配时渲染。
  • children:嵌套路由。
  • redirect:路由重定向。
  • beforeEnter:路由导航守卫。
  • props:允许将参数作为 props 传递给由 router-view 渲染的组件。
  • meta:路由元信息,一个包含自定义信息的对象,用于存储路由的额外信息,如路由标题、是否需要登录等。这个对象可以在路由守卫(如在导航守卫中使用to.meta.requiresAuth)中被访问,用于控制路由的访问权限、添加页面标题等。
    • meta.title:路由标题。
    • meta.requiresAuth:是否需要登录。
    • meta.keepAlive:是否缓存路由组件。
    • meta.icon:路由图标。
    • meta.hidden:是否在菜单中隐藏。
    • meta.activeMenu:激活菜单。
    • meta.breadcrumb:面包屑信息。

1.4 动态路由匹配

动态路由匹配是指根据当前路由路径,动态匹配出对应的路由组件。在 Vue Router 中,我们可以使用 :id 等动态参数来匹配路由路径。

import User from './User.vue'

const routes = [
  
  { path: '/users/:id', component: User },
]

路径参数 用冒号 : 表示。当一个路由被匹配时,它的 params 的值将在每个组件中以 route.params 的形式暴露出来。

template>
  div>
    
    User {{$route.params.id}}
  div>
template>

可以在同一个路由中设置有多个 路径参数,它们会映射到 $route.params 上的相应字段

匹配模式 匹配路径 $route.params
/users/:username /users/ayla {username: 'ayla'}
/users/:username/ids/:id /users/ayla/ids/001 {username: 'ayla', id: '001'}

常规参数只匹配 url 片段之间的字符,用 / 分隔。如果想 匹配任意路径 ,我们可以使用自定义的 路径参数 正则表达式,在 路径参数 后面的括号中加入 正则表达式 :

const routes = [
  
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
  
  { path: '/user-:afterUser(.*)', component: UserGeneric },
]

更多的动态路由匹配规则,可以参考 vue router 4 官方文档 路由的匹配语法 部分

注意
使用带有参数的路由时,当用户从 /users/johnny 导航到 /users/marry 时,相同的组件实例将被重复使用(因为两个路由都渲染同个组件,比起销毁再创建,复用会更加高效)。不过,这也意味着组件的生命周期钩子不会被调用。
若要对同一个组件中参数的变化做出响应的话,可以 watch $route.params 或者在路由守卫 beforeRouteUpdate 做出响应。

1.5 路由传参

1.5.1 query 参数

传递参数


router-link to="/news/detail?a=1&b=2&content= 欢迎你">
  跳转
router-link>
        

RouterLink 
  :to="{
    //name:'detail', // 用 name 也可以跳转
    path:'/news/detail',
    query:{
      id:news.id,
      title:news.title,
      content:news.content
    }
  }"
>
  {{news.title}}
RouterLink>

接收参数

import {useRoute} from 'vue-router'
const route = useRoute()

console.log(route.query)
1.5.2 params 参数

传递参数


RouterLink :to="`/news/detail/001/ 新闻 001/ 内容 001`">{{news.title}}RouterLink>
        

RouterLink 
  :to="{
    name:'detail', // 用 name 跳转
    params:{
      id:news.id,
      title:news.title,
      content:news.title
    }
  }"
>
  {{news.title}}
RouterLink>

接收参数

import {useRoute} from 'vue-router'
const route = useRoute()

console.log(route.params)
1.5.3 路由的 props 配置

可以将路由参数作为 props 传给组件

const routes = [{
  name: 'detail',
  path: 'detail/:id/:title/:content',
  component: Detail,

  
  
  
  
  

  
  props: route => ({ id: route.params.id, sort: route.query.sort })
}]

接收参数

template>
  div>
    p>User ID: {{ id }}/p>
    p>Sort Order: {{ sort }}/p>
  /div>
/template>

script setup>







defineProps(['id', 'sort']);
/script>

1.6 导航方式

声明式 编程式
router.push(...)
  • 编程式导航 :通过JavaScript 代码来进行页面的跳转和切换。Vue Router提供了一些方法来实现这种导航方式,如 router.pushrouter.replacerouter.go

  • 声明式导航 :通过在模板中声明的方式来进行页面的切换和跳转。在Vue Router 中,可以使用 组件来实现声明式导航。组件可以被渲染为一个 标签,用于通过路由链接跳转页面。例如:Home

router.push:会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL


router.push('/users/eduardo')

router.push({ path: '/users/eduardo' })

router.push({ name: 'user', params: { username: 'eduardo' } })

router.push({ path: '/register', query: { plan: 'private' } })

router.push({ path: '/about', hash: '#team' })

router.replace:类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录。

router.push({ path: '/home', replace: true })

router.replace({ path: '/home' })

router.go:该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步。


router.go(1)

router.go(-1)

router.go(3)

router.go(-100)
router.go(100)

1.7 历史模式

在创建路由器实例时,history 配置允许我们在不同的历史模式中进行选择。

  • Hash 模式: createWebHashHistory() – 地址带 # 号,不需要服务器配置,不利于SEO
  • HTML5 模式: createWebHistory() – 不带 # 号,需要适当的服务器配置,否则刷新会有 404 错误。
  • Memory 模式: createMemoryHistory() – 不会假定自己处于浏览器环境,不会与 URL 交互也不会自动触发初始导航,不能前进或后退,适合 Node 环境和 SSR
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(), 
  routes: [
    
  ],
})

1.8 导航守卫

a. 全局前置守卫 (beforeEach)
b. 全局解析守卫 (beforeResolve)
c. 全局后置钩子 (afterEach)
d. 路由独享守卫 (beforeEnter)
e. 组件内的守卫 (beforeRouteEnter, beforeRouteUpdate, beforeRouteLeave)
1.8.1 全局前置守卫

router.beforeEach():全局前置守卫是最常用的守卫之一。当一个导航触发时,全局前置守卫会按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。

 router.beforeEach(async (to, from) => {
   if (
     
     !isAuthenticated &&
     
     to.name !== 'Login'
   ) {
     
     return { name: 'Login' }
   }
 })

参数:

  • to:即将跳转的路由
  • from:当前导航正要离开的路由
  • next(可选): 在之前的 Vue Router 版本中,还可以使用 第三个参数 next。这是一个常见的错误来源,vue官方经过 RFC 讨论将其移除。然而,目前 next 仍然可以使用,这意味着你可以向任何导航守卫传递第三个参数。在这种情况下,需要确保 next 在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错。

返回值:

  • false: 取消当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  • 一个路由地址:通过一个路由地址重定向到一个不同的地址,如同调用 router.push(),且可以传入诸如 replace: truename: 'home' 之类的选项。它会中断当前的导航,同时用相同的 from 创建一个新导航。
  • undefined 或者 true:导航是有效的,之后会按流程调用下一个导航守卫。
1.8.2 全局解析守卫

router.beforeResolve():与 router.beforeEach 类似,在每次导航时都会触发,不同的是,解析守卫刚好会在导航被确认之前、所有组件内守卫和异步路由组件被解析之后调用。

因此,router.beforeResolve 是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。

router.beforeResolve(async to => {
  if (to.meta.requiresCamera) {
    try {
      await askForCameraPermission()
    } catch (error) {
      if (error instanceof NotAllowedError) {
        
        return false
      } else {
        
        throw error
      }
    }
  }
})
1.8.3 全局后置钩子

router.afterEach():与前置守卫不同的是,全局后置钩子不会接受 next 函数也不会改变导航本身。

利用它可以完成分析、更改页面标题、声明页面等辅助功能。

router.afterEach((to, from) => {
  sendToAnalytics(to.fullPath)
  
})
1.8.4 路由独享守卫

beforeEnter:路由独享守卫是针对单个路由的守卫,可以定义在路由配置中。

beforeEnter 守卫 只在进入路由时触发,不会在 paramsqueryhash 改变时触发。例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects。它们只有在 从一个不同的 路由导航时,才会被触发。

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/protected',
      beforeEnter: (to, from, next) => {
        if (store.getters.isLoggedIn) {
          next();
        } else {
          next('/login');
        }
      },
      component: ProtectedComponent
    }
  ]
});
1.8.5 组件内的守卫

组件级别的守卫可以定义在组件内,包括进入前守卫、更新前守卫和离开前守卫。

beforeRouteEnter:在进入路由之前被调用。
beforeRouteUpdate:在当前路由改变,但是该组件被复用时调用。
beforeRouteLeave:在离开路由之前被调用。

script>
export default {
  beforeRouteEnter(to, from) {
    
    
    
  },
  beforeRouteUpdate(to, from) {
    
    
    
    
  },
  beforeRouteLeave(to, from) {
    
    
  },
}
/script>

1.9 动态路由

对路由的添加通常是通过 routes 选项来完成的,但是在某些情况下,可能需要在应用程序已经运行的时候添加或删除路由。

1.9.1 添加路由

假设目前只有一个路由:

const router = createRouter({
  history: createWebHistory(),
  routes: [{ path: '/:articleName', component: Article }],
})

此时,进入任何页面,例如 /about/article,都会被匹配到 Article 页面。若此时利用 router.addroute 添加/about 路由:

router.addRoute({ path: '/about', component: About })

页面仍然会显示 Article 组件,我们需要手动调用 router.replace() 来改变当前的位置,并覆盖原来的位置:

router.addRoute({ path: '/about', component: About })

router.replace(router.currentRoute.value.fullPath)

*注意:如果需要等待新的路由显示,可以使用 await router.replace()

如果需要在导航守卫内部添加或删除路由,不应该调用 router.replace(),而是要通过返回新的位置来触发重定向:

router.beforeEach(to => {
  if (!hasNecessaryRoute(to)) {
    router.addRoute(generateRoute(to))
    
    return to.fullPath
  }
})
1.9.2 删除路由
  • 通过添加一个名称冲突的路由。如果添加与现有途径名称相同的途径,会先删除路由,再添加路由:
router.addRoute({ path: '/about', name: 'about', component: About })

router.addRoute({ path: '/other', name: 'about', component: Other })
  • 通过调用 router.addRoute() 返回的回调:
const removeRoute = router.addRoute(routeRecord)
removeRoute() 
  • 通过使用 router.removeRoute() 按名称删除路由:
router.addRoute({ path: '/about', name: 'about', component: About })

router.removeRoute('about')

*注意:当路由被删除时,所有的别名和子路由也会被同时删除

1.9.3 添加嵌套路由

要将嵌套路由添加到现有的路由中,可以将路由的 name 作为第一个参数传递给 router.addRoute()

router.addRoute({ name: 'admin', path: '/admin', component: Admin })
router.addRoute('admin', { path: 'settings', component: AdminSettings })


router.addRoute({
  name: 'admin',
  path: '/admin',
  component: Admin,
  children: [{ path: 'settings', component: AdminSettings }],
})
1.9.4 查看现有路由
router.hasRoute():检查路由是否存在。router.getRoutes():获取一个包含所有路由记录的数组。

1.10 router 与 route

  • routerVue Router 的实例,它代表了整个路由系统。可以在组件的 setup 函数中通过 useRouter 函数获取到这个实例。router实例提供了全局的路由控制功能,如编程式导航(使用 pushreplace 等方法)、监听路由变化(通过 beforeEachafterEach 等钩子函数)等。

  • route是当前激活的路由信息对象,它包含了当前 URL 解析得到的信息。可以在组件的 setup 函数中通过 useRoute 函数获取到这个对象。route对象用于访问当前路由的状态信息,如路径、查询参数、哈希值、路由参数等。

router 实例的属性和方法
Vue router 4 基础知识讲解

import { useRouter } from 'vue-router'

const router = useRouter()

router.options 
router.currentRoute 
router.listening 
router.addRoute(name, route) 
router.afterEach(to, from) 
router.beforeEach(to, from) 
router.beforeResolve(to, from) 
router.clearRoutes() 
router.removeRoute(name) 
router.hasRoute(name) 
router.getRoutes() 
router.go(n) 
router.back() 
router.forward() 
router.push(to) 
router.replace(to) 
router.install(app) 
router.resolve(to, currentLocation?) 
router.isReady() 
router.onError(errorHandler) 

route 对象的属性
Vue router 4 基础知识讲解

import { useRoute } from 'vue-router'

const route = useRoute()

console.log(route.fullPath) 
console.log(route.hash) 
console.log(route.matched) 
console.log(route.meta) 
console.log(route.name) 
console.log(route.params) 
console.log(route.path) 
console.log(route.query) 
console.log(route.redirectedFrom) 

内容参考:
[1] vue router 4 官方教程

原文地址: Vue router 4 基础知识讲解

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-10-29发表,共计9225字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)