【Vue全家桶】详解Vue Router(二)

本文详细介绍了VueRouter的使用,包括编程式导航的push和replace方法,深入探讨了动态路由的param和query方式,以及导航守卫的全局和局部应用。还讨论了路由懒加载的多种实现方式,如箭头函数+import、webpack和Vite。最后提到了动态添加和删除路由的实践方法。
摘要由CSDN通过智能技术生成

【Vue全家桶】详解Vue Router(二)

Vue系列文章目录

内容参考链接
Vue(一)【Vue全家桶】邂逅Vue、Vue的多种引入方式
Vue(二)【Vue全家桶】声明式编程、MVVM
Vue(三)【Vue全家桶】Options API_
Vue(四)【Vue全家桶】带你全面了解通过Vue CLI初始化Vue项目
Vue(五)【Vue全家桶】组件系列(一)—组件开发基础
Vue(六)【Vue全家桶】组件系列(二)—组件通信(props、$emit、事件总线、Provide、Inject)
Vue(七)【Vue全家桶】详解Vue Router(一)

一、编程式导航

除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。

1.1 push

想要导航到不同的 URL,可以使用 router.push 方法。

  • 这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。
  • 当你点击 <router-link> 时,内部会调用这个方法,所以点击 <router-link :to="..."> 相当于调用 router.push(...)
  • 该方法的参数可以是一个字符串路径,或者一个描述地址的对象。
  • router.push 和所有其他导航方法都会返回一个 Promise,让我们可以等到导航完成后才知道是成功还是失败。
声明式编程式
<router-link :to="...">router.push(...)
// 字符串路径
router.push('/users/eduardo')

// 带有路径的对象
router.push({ path: '/users/eduardo' })

// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })

1.2 replace

它的作用类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。

声明式编程式
<router-link :to="..." replace>router.replace(...)

二、深入动态路由

2.1 param方式

  • 配置路由格式:/router/:id
  • 传递的方式:在path后面跟上对应的值
  • 传递后形成的路径:/router/123

1)路由定义

//在APP.vue中
<router-link :to="'/user/'+userId">用户</router-link>    

//在index.js
{
   path: '/user/:userid',
   component: User,
}

2)路由跳转

// 方法1:
<router-link :to="{ name: 'users', params: { uname: xiaozhang }}">按钮</router-link

// 方法2:
this.$router.push({name:'users',params:{ uname:xiaozhang }})

// 方法3:
this.$router.push('/user/' + xiaozhang)

3)参数获取

通过 $route.params.userid 获取传递的值

2.2 query方式

  • 配置路由格式:/router,也就是普通配置
  • 传递的方式:对象中使用query的key作为传递方式
  • 传递后形成的路径:/route?id=123

1)路由定义

//方式1:直接在router-link 标签上以对象的形式
<router-link :to="{path:'/profile',query:{name:'xiaozhang',age:21,height:152}}">我的</router-link>

// 方式2:写成按钮以点击事件形式
<button @click='profileClick'>我的</button>    

profileClick(){
  this.$router.push({
    path: "/profile",
    query: {
        name: "xiaozhang",
        age: "21",
        height: 188
    }
  });
}

2)跳转方法

// 方法1:
<router-link :to="{ name: 'users', query: { uname: james }}">按钮</router-link>

// 方法2:
this.$router.push({ name: 'users', query:{ uname:james }})

// 方法3:
<router-link :to="{ path: '/user', query: { uname:james }}">按钮</router-link>

// 方法4:
this.$router.push({ path: '/user', query:{ uname:james }})

// 方法5:
this.$router.push('/user?uname=' + jsmes)

3)获取参数

通过$route.query 获取传递的值


三、导航守卫

vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航

3.1 全局前置守卫

你可以使用 router.beforeEach 注册一个全局前置守卫:

router.beforeEach((to, from) => {
  console.log(to)
  console.log(from)
   // 返回 false 以取消导航
   return false
})

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

每个守卫方法接收两个参数:

  • to: 即将要进入的目标
  • from: 当前导航正要离开的路由

可以返回的值如下:

  • false:取消当前导航;
  • 不返回或者undefined:进行默认导航;
  • 返回一个路由地址:
  • 可以是一个string类型的路径;
  • 可以是一个对象,对象中包含path、query、params等信息;
 router.beforeEach(async (to, from) => {
   if (
     // 检查用户是否已登录
     !isAuthenticated &&
     // ❗️ 避免无限重定向
     to.name !== 'Login'
   ) {
     // 将用户重定向到登录页面
     return { name: 'Login' }
   }
 })

其他全局路由守卫

  • 全局解析守卫 router.beforeResolve
    • 注册一个全局守卫。这和 router.beforeEach 类似,因为它在 每次导航时都会触发;
    • 但是确保在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用
    • router.beforeResolve 是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。
  • 全局后置钩子afterEach
    • 它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。

3.2 路由独享的守卫

  • 路由独享的守卫beforeEnter
    • beforeEnter 守卫 只在进入路由时触发,不会在 paramsqueryhash 改变时触发。
    • 可以将一个函数数组传递给 beforeEnter,这在为不同的路由重用守卫时很有用

3.3 组件内的守卫

  • beforeRouteEnter
    • beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
    • 可以通过传一个回调给 next 来访问组件实例。
  • beforeRouteUpdate
  • beforeRouteLeave

3.4 完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫(2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

四、路由懒加载

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。

  • 如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效;
  • 也可以提高首屏的渲染效率;

4.1 使用箭头函数+import动态加载

Vue Router默认就支持动态来导入组件:

  • 这是因为component可以传入一个组件,也可以接收一个函数,该函数 需要放回一个Promise
  • import函数就是返回一个Promise
// 将
// import UserDetails from './views/UserDetails.vue'
// 替换成
const UserDetails = () => import('./views/UserDetails.vue')

const router = createRouter({
  // ...
  routes: [{ path: '/users/:id', component: UserDetails }],
})

4.2 使用 webpack

有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4):

const UserDetails = () =>
  import(/* webpackChunkName: "group-user" */ './UserDetails.vue')
const UserDashboard = () =>
  import(/* webpackChunkName: "group-user" */ './UserDashboard.vue')
const UserProfileEdit = () =>
  import(/* webpackChunkName: "group-user" */ './UserProfileEdit.vue')

webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。

4.3使用 Vite

在Vite中,你可以在rollupOptions下定义分块:

// vite.config.js
export default defineConfig({
  build: {
    rollupOptions: {
      // https://rollupjs.org/guide/en/#outputmanualchunks
      output: {
        manualChunks: {
          'group-user': [
            './src/UserDetails',
            './src/UserDashboard',
            './src/UserProfileEdit',
          ],
        },
      },
    },
  },
})

五、动态路由

动态路由主要通过两个函数实现。router.addRoute()router.removeRoute()

5.1 动态添加路由

  • 只注册一个新的路由;
    • 也就是说,如果新增加的路由与当前位置相匹配,就需要你用 router.push()router.replace()手动导航,才能显示该新路由。
router.addRoute({ path: '/about', component: About })

要将嵌套路由添加到现有的路由中,可以将路由的 name 作为第一个参数传递给 router.addRoute(),这将有效地添加路由,就像通过 children 添加的一样:

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 }],
})

5.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')
    

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

写在最后

🫡这里是前端程序员小张

🌟创作不易,希望各位大佬支持一下

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端程序员小张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值