能够构建出色的单页应用程序(SPA)是 Vue.js 最具有吸引力的功能之一。
SPA 非常好,因为它们不需要在每次更改路由时都去加载页面。这就意味着一旦加载了全部内容,就可以真正快速地对视图进行切换,并提供出色的用户体验。
如果你想要基于 Vue 去构建 SPA,则需要 Vue 路由。
在本教程中,我将介绍设置 Vue Router 的基础知识,并研究一些更高级的技术,例如:
动态路由匹配
导航挂钩(Navigation Hook)
Vue 路由是什么?
Vue 路由有助于在浏览器的 URL 或历史记录与 Vue 组件之间建立链接,从而允许某些路径渲染与之关联的任何一个视图。
VueCore 小组成员 Eduardo San Martin Morote 在他的 VueConf Toronto演讲中,对 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 元素为 Vue Router 提供了一个位置,用来渲染当前 URL 被解析后对应的组件。
对于这个例子,我们将其放在 App.vue 根组件中。再添加一些链接,以便可以在两个路由之间切换。 Vue Router 使用称为 的特殊链接元素,这些元素的 to 属性能够映射到组件。
Home
Profile
运行我们的应用时,应该能够看到 home 组件渲染。如果单击路由链接元素,那么内容将会被更改,同时 URL 也会更改!
下面深入了解 Vue Router 的更多细节。
以编程方式更改路由
在前面的示例中,我们使用 在不同的路线之间导航。从本质上讲,这些等效于 Vue Router 的 标签(实际上,它们可以编译为 标签)。
但是另一种更改路由的方法是用 router.push 方法以编程方式进行导航。与使用 类似,router.push 接受通过使用其路径或名称的字符串或对象映射到一个路由。
this.$router.push({ path: '/profile' })
// OR
this.$router.push({ name: 'profile' })
使用此方法传递 URL 参数或查询也很容易。只需要添加一个 params 或 query 参数即可。
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,有两种方法可以实现。
我们的 postID 可以通过 $route.params 对象在 ArticlePage 中访问
我们可以把文章 ID 作为 prop 传递给你的组件。
我推荐使用第二种方法,因为它可以使你构建更多的不依赖于特定 URL 格式的可重用组件。
只需在路线中添加 props:true 即可。添加该属性后,我们的动态路由应如下所示。
{
path: '/post/:postID',
props: true,
name: 'post',
component: ArticlePage
}
在组件中,必须确保在声明 prop 时要与在路由中声明的名称相同。
{{ postID }}
export default {
props: {
postID: String
}
}
在更完整的项目中,我们通常会采用路由传递的 prop 值,并通过 API 调用来加载相应的内容。但是一旦可以访问组件内部的 prop 时,就可以使用它进行任何操作。
导航守护简介
导航守护是 Vue Router 中更高级的内容之一。它们是路由过程中的 Hook,可让你重定向、取消或修改导航。
导航守护有三种类型:
全局守护
特定路由的守护
在组件中的守护
此外,守护可以接受三个参数:
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 的演讲之后,我认为后续可能还会有更多的改进!