专栏首页京程一灯深入探索 Vue 路由

深入探索 Vue 路由

// 每日前端夜话 第360篇
// 正文共:2896 字
// 预计阅读时间:10 分钟

能够构建出色的单页应用程序(SPA)是 Vue.js 最具有吸引力的功能之一。

SPA 非常好,因为它们不需要在每次更改路由时都去加载页面。这就意味着一旦加载了全部内容,就可以真正快速地对视图进行切换,并提供出色的用户体验。

如果你想要基于 Vue 去构建 SPA,则需要 Vue 路由。

在本教程中,我将介绍设置 Vue Router 的基础知识,并研究一些更高级的技术,例如:

  • 动态路由匹配
  • 导航挂钩(Navigation Hook)

Vue 路由是什么?

Vue 路由有助于在浏览器的 URL 或历史记录与 Vue 组件之间建立链接,从而允许某些路径渲染与之关联的任何一个视图。

VueCore 小组成员 Eduardo San Martin Morote 在他的 VueConf Toronto演讲[1]中,对 Vue 路由背后的设计思想做了大量的分享。

Morote 讨论了在灵活的路由(开发人员有更多的自主权,但是需要编写更多的代码)与死板的路由(开发人员拥有的自主权较少,但是路由涵盖了更多的应用场景)之间进行权衡时,其背后的决策过程。

基于配置的 Vue 路由旨在为开发人员提供用于常见应用场景的工具,并灵活应对独特的问题。

在继续介绍一些更高级的 Vue 路由之前,先了解一下基础知识。

Vue 路由的快速设置

首先是快速创建一个 Vue Router 的简单例子。

虽然你可以用 vue-cli 轻松添加 Vue 路由,但是我认为你应该知道该怎样自己进行操作。这样才能够真正了解Vue 路由的每个细节。

首先用 npm install vue-router 把 Vue Router 添加到我们的项目中。然后通过 src/main.js 文件将其包含在 Vue 实例中。

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

完成所有设置后,开始创建路由。

在 src 内,创建一个 src/router 文件夹,其中的 index.js 文件包含以下内容。

import Vue from 'vue'
import VueRouter from  'vue-router'
import Home from '../views/Home.vue'
import Profile from '../views/Profile.vue'

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    name: "home",
    component: Home
  },
  {
    path: '/profile',
    name: 'profile',
    component: Profile
  }
]

const router = new VueRouter({
  mode: 'history',
  routes
})

export default router

这个代码段用了两个路由组件匹配来初始化 Vue Router。我不会在这里介绍 Home 和 Profile 组件的详细信息,你只需要假设它们分别输出 “home” 和 “profile” 就行了。

显示路由视图

前面已经设置了 Vue 路由,但是还没有查看效果的方式。

这时就需要 <router-view> 元素发挥作用了。从本质上讲,router-view 元素为 Vue Router 提供了一个位置,用来渲染当前 URL 被解析后对应的组件。

对于这个例子,我们将其放在 App.vue 根组件中。再添加一些链接,以便可以在两个路由之间切换。Vue Router 使用称为 <router-link> 的特殊链接元素,这些元素的 to 属性能够映射到组件。

<template>
  <div id="app">
    <router-link to='/'>Home</router-link>
    <router-link to='/profile'>Profile</router-link>
    <router-view  />
  </div>
</template>

运行我们的应用时,应该能够看到 home 组件渲染。如果单击路由链接元素,那么内容将会被更改,同时 URL 也会更改!

下面深入了解 Vue Router 的更多细节。

以编程方式更改路由

在前面的示例中,我们使用 <router-link> 在不同的路线之间导航。从本质上讲,这些等效于 Vue Router 的<a> 标签(实际上,它们可以编译为 <a> 标签)。

但是另一种更改路由的方法是用 router.push 方法以编程方式进行导航。与使用 <router-link> 类似,router.push 接受通过使用其路径或名称的字符串或对象映射到一个路由。

this.$router.push({ path: '/profile' })
// OR
this.$router.push({ name: 'profile' })

使用此方法传递 URL 参数或查询也很容易。只需要添加一个 paramsquery 参数即可。

this.$router.push({ 
        path: '/profile', 
        params: { username: 'helloworld' }, 
        query: { source:  'tutorial' } 
    })

历史记录模式和哈希模式之间的区别

Vue 路由的 URL 有两种模式:历史记录和哈希模式。

  • 「哈希模式(默认)」——使用 URL 哈希来模拟 URL,例如 mypage.com/#profile
  • 「历史记录」——看起来像一个典型的 URL,并使用 history.pushState 来避免页面被重新加载;例如mypage.com/profile

我们的路由用了历史记录模式,因为我个人喜欢标准 URL 外观。

处理动态路由

你可以把 URL 模式与组件进行匹配,而不必对每个可能的路径进行硬编码。这对于配置文章页面、个人资料页面和其他可以动态创建或删除的内容非常有用。

用冒号 : 在 Vue 路由中定义动态路径。例如,如果我们要动态匹配文章页面,则路由应如下所示。

{
  path:  '/post/:postID',
  name:  'post',
  component:  ArticlePage
}

这个路由会把所有遵循 /post/:postID 模式的 URL 导航到相同的 ArticlePage.vue 组件。

如果想要在组件内部获取 postID,有两种方法可以实现。

  1. 我们的 postID 可以通过 $route.params 对象在 ArticlePage 中访问
  2. 我们可以把文章 ID 作为 prop 传递给你的组件。

我推荐使用第二种方法,因为它可以使你构建更多的不依赖于特定 URL 格式的可重用组件。

只需在路线中添加 props:true 即可。添加该属性后,我们的动态路由应如下所示。

{
  path:  '/post/:postID',
  props: true,
  name:  'post',
  component:  ArticlePage
}

在组件中,必须确保在声明 prop 时要与在路由中声明的名称相同。

<template>
  <div>
    {{ postID }}
  </div>
</template>
<script>
export  default {
  props: {
    postID:  String
  }
}
</script>

在更完整的项目中,我们通常会采用路由传递的 prop 值,并通过 API 调用来加载相应的内容。但是一旦可以访问组件内部的 prop 时,就可以使用它进行任何操作。

导航守护简介

导航守护是 Vue Router 中更高级的内容之一。它们是路由过程中的 Hook,可让你重定向、取消或修改导航。

导航守护有三种类型:

  1. 全局守护
  2. 特定路由的守护
  3. 在组件中的守护

此外,守护可以接受三个参数:

  • to:我们要到达的那个路由
  • from:要离开的路由
  • next:用于解决 Hook 的函数;根据传递给下一个方法的参数,我们的路由将处理不同的导航
  • next(false):中止导航,不离开 from 路由
    • next('/ home'):把我们的导航重定向到指定的路由
  • next():如果没有参数,则会简单地将其移至下一个 Hook;确认导航没有剩余的Hook

1. 全局守护

全局守护的措施主要有两种:router.beforeEach()router.afterEach() 分别在导航解析之前和之后运行。

让我们来看一个例子。在此方法中,首先检查用户是否有权访问某个页面,如果没有访问权,将会阻止路由解析。请注意,每次 Hook 运行时仅调用一次。

router.beforeEach( (to, next, from) => {
  if (to.path === '/profile') {
    if (!hasAccess(to.path)) { // just some arbitrary conditional
     next(false) // deny access to this page
    } else {
     next() // keep moving on to next hook
    }
  } else {
    next() // keep moving on to next hook
  }
})  

2. 特定于路由的守护

当我们在 Vue Router 中声明路由时,还可以添加一个 beforeEnter 函数,其功能类似于全局 beforeEach 路由,但是它可以包含特定于路由的逻辑。

{
  path:  '/post/:postID',
  props:  true,
  name:  'post',
  component:  ArticlePage,
  beforeEnter: (to, from, next) => {
    // some logic here
  }
}

3.在组件中的守护

更具体地说,我们可以在组件的 options 对象中插入导航守护,总共有三种:

  • beforeRouteEnter (to, from, next):在确认此路由之前调用;该组件尚未创建。
  • beforeRouteUpdate (to, from, next) :在切换路由时调用;但新路由也可以确定此组件。
  • beforeRouteLeave(to, from, next):当离开这个组件时被调用

需要注意的是,在确认导航之前和实际创建组件之前,将会调用 beforeRouteEnter。此时我们还没有访问this

为了解决这个问题,beforeRouteEnter 允许我们将回调传给下一个方法,该方法将在组件实际创建后立即执行。

beforeRouteEnter (to, from, next) {
  next((vm) => {
    // vm = 'this'
 console.log(vm)
  })
}

总结

希望本文能够帮你你学习一些基本和高级的 Vue 路由技术。

探索一个灵活但易用的路由所涉及的设计思路非常很有趣。在听过 Morote 的演讲之后,我认为后续可能还会有更多的改进!


# 作者:Matt Maribojoc
# 翻译:疯狂的技术宅
# 原文:https://vuejsdevelopers.com/2020/01/27/closer-look-at-vue-router/

Reference

[1]VueConf Toronto演讲:https://www.youtube.com/watch?v=mbbal-ZW0ho

本文分享自微信公众号 - 前端先锋(jingchengyideng),作者:疯狂的技术宅

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一文学会Vue中间件管道[每日前端夜话0x8C]

    通常,在构建SPA时,需要保护某些路由。例如假设有一个只允许经过身份验证的用户访问的 dashboard 路由,我们可以通过使用 auth 中间件来确保合法用户...

    疯狂的技术宅
  • 实战!半小时写一个脑力小游戏 [每日前端夜话0x21]

    本实战使用了HTML5,CSS3和JavaScript的基本的技术。 我们将讨论数据属性、定位、透视、转换、flexbox、事件处理、超时和三元组。 你不需要在...

    疯狂的技术宅
  • 深入理解Shadow DOM v1[每日前端夜话0x63]

    shadow DOM不是超级英雄电影中的恶棍,也不是DOM的黑暗面。 shadow DOM只是一种解决文档对象模型(或简称DOM)中缺少的树封装方法。

    疯狂的技术宅
  • 「vue基础」Vue Router 使用指南上篇(文末送漂亮的 Vue 站点源码)

    大家好,今天的内容,我将和大家一起聊聊 Vue 路由相关的知识,如果你以前做过服务端相关的开发,那你一定会对程序的URL结构有所了解,我没记错的话也是路由映射的...

    前端达人
  • thinkphp 路由

    http://localhost:8082/admin/blog/23/ 此时会匹配23内容

    mySoul
  • 《深入理解mybatis原理》 Mybatis初始化机制详解

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://louluan.blo...

    亦山
  • 当面试官问我Mybatis初始化原理时,我笑了

    来源:blog.csdn.net/luanlouis/article/details/37744073

    Java团长
  • DjangoRestFramework,restful规范、APIview、解析器组件、Postman等

      大家还记得CBV的这个视图函数,为什么get请求就能找到类的get方法,post请求就能找到post方法,其内部有个dispatch方法来进行分发,这又怎么...

    changxin7
  • CCNP学习笔记(3)

    一、RIPv2:Routing Information Protocol 路由信息协议

    py3study
  • 数据结构 链表(循环)

    #include<stdio.h> #include<malloc.h> #include<stdlib.h> //函数状态码定义 #define TRUE ...

    Kindear

扫码关注云+社区

领取腾讯云代金券