vue-router4.x入门

37 阅读4分钟

引入

  • 创建工程时默认安装配置
  • 手动配置
    • 安装npm i vue-router
    • 初始化路由设置
      1. 创建src/router/index.js
      import { createRouter, createWebHistory } from 'vue-router'
      const routes = [
        {
          path: "/demo1",
          name: "DemoOne",
          component: () => import('../views/DemoOne/index.vue')
        },
        {
          path: "/demo2",
          name: "DemoTwo",
          component: () => import('../views/DemoTwo/index.vue')
        }
      ]
      
      1. main.js中挂载
      const app = createApp(App)
      app.use(router)
      app.mount('#app')
      
      1. 相关页面中使用
        <RouterLink to="/demo1">页面1</RouterLink>
        <RouterLink to="/demo2">页面2</RouterLink>
        <RouterView></RouterView>
      

    router-link组件是一个自定义的链接组件允许在不重新加载页面的情况下更改页面的URL, router-view用来渲染与当前URL对应的组件,我们可以将其放在任何位置

带参动态路由

参数获取

在组件中使用路由的参数有以下两种方法:

  1. 传统方式
// dom中
<template>
  <p>姓名:{{ $route.params.username }}</p>
  <p>年龄:{{ $route.params.age }}</p>
</template>
// js中
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.age)
  1. props方式
// 路由中新增props属性
const routes = [
  {
    path: "/user/:username/:age",
    name: "UserDemo",
    component: () => import('../views/UserDemo/index.vue'),
    props: true
  }
]

// 组件中
<template>
  <p>{{ age }}</p>
</template>
<script setup>
const props = defineProps(['username', 'age'])
console.log(props.username, props.age)
</script>

// props参数的改造, 在自定义props后,路由中的参数就不能用了,需要用props对象
props: { id: 'xx' } // id固定值为'xx'
props:route => {
    return {
        age: route.params.age,
        id: 'xxx'
    }
    
}

路由参数匹配

  1. 路由指向的组件,由路由参数决定页面的渲染内容($route.params.username获取参数)
<template>
  <p>姓名:{{ $route.params.username }}</p>
  <p>年龄:{{ $route.params.age }}</p>
</template>
  1. 在路由文件(src/router/index.js)定义含参数的路由,访问地址/user/zs/19
const routes = [
  // ...
  {
    path: "/user/:username/:age",
    name: "UserDemo",
    component: () => import('../views/UserDemo/index.vue')
  }
]
  1. 页面变化获取参数
import { onBeforeRouteUpdate } from 'vue-router'

onBeforeRouteUpdate((to, from) => {
  console.log(to, from)
  alert(`name: ${to.params.username}, age: ${to.params.age}`)
})
onMounted(() => {
   alert("xxxx")
})

ps: 当/user/zs/19->/user/ls/11直接变化时,是第二次是不会触发user组件生命周期的(可以通过路由守卫来获取变化参数),但是/user/zs/19->/demo1->/user/ls/11,每次都会触发user组件的生命周期

路由匹配的语法规则

假设用户(user)路由下有设置页面和个人主页,一般跳转可以用以下两种方式

  1. 直接区分
/user/setting/:id
/user/person/:username

2. 正则匹配

用户中心页面和用户设置页面所需要的参数类型有明显的差异,假设用户编号必须是数值,而用户名不能是纯数字,我们可以通过正则约束来实现将不同类型的参数匹配到对应的路由组件

/user/:id(\\d+)
/user/person/:username

常见的正则路由

1. 参数可以为空
/user/:username?
2. 参数收集
/user/:cat*
(当路由为/user/1/2/3时cat参数值为[1,2,3])

路由嵌套

首页导航栏,有几个组件对应了路由,渲染了页面

image.png 如果新闻公告页面还需要路由,就需要使用嵌套路由:

  • 路由配置
const routes = [
    // 一级路由
    path: '/news'
    component: News
    // 子路由
    children: [
        {
            path: 'detail',
            component: NewsDetail
        }
    ]
]
  • 渲染位置News组件
<template>
    ...
    <router-view></router-view>
    ...
</template>

js控制页面导航

两个关键的函数: useRouter针对所有的路由控制、useRoute针对当前路由

页面跳转(push)

const route = useRouter()
const pushRouter = () => {
  route.push(
    {
      name: 'UserDemo', params: { username: 'ww', age: 18 }
    }).then(() => {
      console.log('导航成功')
    }).catch(() => {
      console.log('导航失败')
    })
  // route.push({ path: '/user/ww/18' })
  // route.push({ path: '/user', query: { username: 'ww', age: 18 } })
}

路由视图命名

一个路由页面需要渲染多个子组件或页面,需要对进行命名,默认为default

// 1. 页面部分
  <RouterView name="view1"></RouterView>
  <RouterView name="view2"></RouterView>
// 2. 路由部分
  {
    path: '/home/:username/:age',
    components: {
      view1: () => import('../views/DemoOne/index.vue'),
      view2: () => import('../views/UserDemo/index.vue')
    }
  },

路由别名和重定向

路由别名是在路由配置中加一个别名选项, path: '/demo1', alias: ['/d1']在浏览器输入/demo1或/d1都是到一个页面,浏览器路径输入哪个就显示哪个;重定向是单独一个配置,浏览器输入也会变成配置相关

{
    path: "/demo1",
    name: "DemoOne",
    alias: ['/d1'], // 别名
    // 浏览器输入 /demo1 /d1 都是定位到相同的组件
    component: () => import('../views/DemoOne/index.vue')
  },
  {
    path: '/xxx', redirect: '/demo1' // 重定向
    // 浏览器输入/xxx会直接变成/demo1
  },

路由守卫

flowchart TD
    A[导航被触发] --> B[调用 beforeRouteLeave 守卫]
    B --> C[调用全局 beforeEach 守卫]
    C --> D{组件是否没有变化?}
    D -->|是| E[调用 beforeRouteUpdate 守卫]
    D -->|否| F[调用 beforeEnter 守卫]
    E --> F
    F --> G[解析异步路由组件]
    G --> H[导航被确认]
    H --> I[调用全局 afterEach 守卫]

路由守卫有三种:

  1. 全局钩子: beforeEach、 afterEach(路由切换前、后调用)
router.beforeEach((to, from, next) => {
    //如果路由需要跳转
    if (to.meta.isAuth) {
        //判断 如果school本地存储是qinghuadaxue的时候,可以进去
        if (localStorage.getItem('school') === 'qinghuadaxue') {
            next()  //放行
        } else {
            alert('抱歉,您无权限查看!')
        }
    } else {
        // 否则,放行
        next()
    }
})
  1. 独享守卫(单个路由里面的钩子): beforeEnter、 beforeLeave
    {
        path: '/',
        name: 'Home',
        component: () => import('../views/Home.vue'),
        meta: { isAuth: true },
        beforeEnter: (to, from, next) => {
            if (to.meta.isAuth) { //判断是否需要授权
                if (localStorage.getItem('school') === 'qinghuadaxue') {
                    next()  //放行
                } else {
                    alert('抱歉,您无权限查看!')
                }
            } else {
                next()  //放行
            }
        }
    },
  1. 组件内守卫(直接放在.vue文件中):beforeRouteEnter、 beforeRouteUpdate、 beforeRouteLeave
//通过路由规则,进入该组件时被调用
beforeRouteEnter(to,from,next) {
  if(toString.meta.isAuth){
    if(localStorage.getTime('school')==='qinghuadaxue'){
      next()
    }else{
      alert('学校名不对,无权限查看!')
    }
  } else{
    next()
  }
},
 
//通过路由规则,离开该组件时被调用 
beforeRouteLeave(to,from,next) {
 next()
}

动态路由

动态操作路由的方法主要有两个:addRoute和removeRoute; 动态操作路由的方法主要有两个:addRoute和removeRoute