基本使用
html:
<script src="https://unpkg.com/vue/dist/vue.js"></script> ="https://unpkg.com/vue-router/dist/vue-router.js"> div id="app"> h1>Hello App!</p> <!-- 使用 router-link 组件来导航. --> 通过传入 `to` 属性指定链接. <router-link> 默认会被渲染成一个 `<a>` 标签 router-link to="/foo">Go to Foorouter-link="/bar">Go to Bar 路由出口 --> 路由匹配到的组件将渲染在这里 router-viewdiv>
JavaScript:
// 0. 如果使用模块化机制编程,導入Vue和VueRouter,要调用 Vue.use(VueRouter) 1. 定义(路由)组件。 // 可以从其他文件 import 进来 const Foo = { template: '<div>foo</div>' } const Bar = { template: '<div>bar</div>' } 2. 定义路由 每个路由应该映射一个组件。 其中"component" 可以是 通过 Vue.extend() 创建的组件构造器, 或者,只是一个组件配置对象。 我们晚点再讨论嵌套路由。 const routes = [ { path: '/foo',component: Foo },{ path: '/bar' 3. 创建 router 实例,然后传 `routes` 配置 你还可以传别的配置参数,不过先这么简单着吧。 const router = new VueRouter({ routes (缩写)相当于 routes: routes }) 4. 创建和挂载根实例。 记得要通过 router 配置参数注入路由, 从而让整个应用都有路由功能 const app = Vue({ router }).$mount('#app') 现在,应用已经启动了!
通过注入路由,我们可以用 this.$router
来访问它,就像在任何组件里用 this.$router
访问当前路有一样。
export default { computed: { username () { 我们很快就会看到 `params` 是什么 return this.$route.params.username } },methods: { goBack () { window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/') } } }
路由的命名
const router = VueRouter({
routes: [
{
path: '/user/:userId'
要链接到一个命名路由,可以给 router-link
的 to
属性传一个对象:
:to="{ name: 'user',params: { userId: 123 }}">User>
这跟代码调用 router.push()
是一回事:
router.push({ name: 'user',params: { userId: 123 }})
这两种方式都会把路由导航到 /user/123
路径。
重定向和别名
const router = VueRouter({ routes: [ { path: '/a',redirect: '/b' } ] })
重定向的目标也可以是一个命名的路由:
const router = }}
]
})
别名:/a
的别名是 /b
,意味着,当用户访问 /b
时,URL 会保持为 /b
,但是路由匹配则为 /a
,就像用户访问 /a
一样。
const router = }
]
})
『别名』的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。
路由组件传参props
方式一:
const User = { template: '<div>User {{ $route.params.id }}</div>' } const router = VueRouter({ routes: [ { path: '/user/:id'const User = { props: ['id'],template: '<div>User {{ id }}</div>' VueRouter({ routes: [ { path: '/user/:id',component: User,props: true }, 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项: { path: '/user/:id': User,sidebar: Sidebar },props: { default: true,sidebar: false } } ] })
如果
props
被设置为true
,route.params
将会被设置为组件属性。
HTML5 History 模式
const router = VueRouter({ mode: 'history'404 错误页面配置:const router =路由元信息Meta
定义路由的时候可以配置
Meta
字段:路由过渡动效
<transition> <router-view></router-view> </transition>上面的用法会给所有路由设置一样的过渡效果,如果你想让每个路由组件有各自的过渡效果,可以在各路由组件内使用
<transition>
并设置不同的 name。const Foo = { template: ` <transition name="slide"> <div class="foo">...</div> </transition> ` } const Bar = { template: ` <transition name="fade"> <div class="bar">...</div> </transition> ` }active-class
设置 链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项
linkActiveClass
来全局配置。<router-link class="uilink" :to="{name:'orgList'}" active-class="active">成员</router-link>嵌套路由
const router = 当 /user/:id/profile 匹配成功, UserProfile 会被渲染在 User 的 <router-view> 中 path: 'profile' 当 /user/:id/posts 匹配成功 UserPosts 会被渲染在 User 的 <router-view> 中 path: 'posts'字符串 router.push('home' 对象 router.push({ path: 'home' }) 命名的路由 router.push({ name: 'user',params: { userId: 123 }}) 带查询参数,变成 /register?plan=private router.push({ path: 'register',query: { plan: 'private' }})注意:如果提供了
path
,params
会被忽略,上述例子中的query
并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的name
或手写完整的带有参数的path
:const userId = 123 router.push({ name: 'user',params: { userId }}) -> /user/123 router.push({ path: `/user/${userId}` }) -> /user/123 这里的 params 不生效 router.push({ path: '/user',1)"> -> /user
router.go(n)
在浏览器记录中前进一步,等同于 history.forward() router.go(1 后退一步记录,等同于 history.back() router.go(-1 前进 3 步记录 router.go(3 如果 history 记录不够用,那就默默地失败呗 router.go(-100) router.go(100)命名视图
有时候想同时(同级)展示多个视图,而不是嵌套展示,例如创建一个布局,有
sidebar
(侧导航) 和main
(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果router-view
没有设置名字,那么默认为default
。router-view class="view one"="view two" name="a"="view three"="b">一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用
components
配置(带上 s):const router = VueRouter({ routes: [ { path: '/': Foo,a: Bar,b: Baz } } ] })导航守卫
全局守卫
你可以使用
router.beforeEach
注册一个全局前置守卫:const router = VueRouter({ ... }) router.beforeEach((to,from,next) => { ... })每个守卫方法接收三个参数:
to: Route
: 即将要进入的目标 路由对象
from: Route
: 当前导航正要离开的路由
next: Function
: 一定要调用该方法来 resolve 这个钩子。执行效果依赖next
方法的调用参数。
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false)
: 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from
路由对应的地址。
next('/')
或者next({ path: '/' })
: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向next
传递任意位置对象,且允许设置诸如replace: true
、name: 'home'
之类的选项以及任何用在router-link
的to
prop 或router.push
中的选项。
next(error)
: (2.4.0+) 如果传入next
的参数是一个Error
实例,则导航会被终止且该错误会被传递给router.onError()
注册过的回调。确保要调用
next
方法,否则钩子就不会被 resolved。全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受
next
函数也不会改变导航本身:router.afterEach((to,from) => ... })
路由独享的守卫
你可以在路由配置上直接定义
beforeEnter
守卫:const router = { ... } } ] })这些守卫与全局前置守卫的方法参数是一样的。
组件内的守卫
const Foo = { template: `...`,beforeRouteEnter (to,next) { 在渲染该组件的对应路由被 confirm 前调用 不!能!获取组件实例 `this` 因为当守卫执行前,组件实例还没被创建 },beforeRouteUpdate (to,1)"> 在当前路由改变,但是该组件被复用时调用 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 可以访问组件实例 `this` 导航离开该组件的对应路由时调用 } }数据获取
有时候,进入某个路由后,需要从服务器获取数据。例如,在渲染用户信息时,你需要从服务器获取用户的数据。我们可以通过两种方式来实现:
导航完成后获取数据
<template> <div class="post"> <div class="loading" v-if="loading"> Loading... </div> <div v-if="error" class="error"> {{ error }} </div> <div v-if="post" class="content"> <h2>{{ post.title }}</h2> <p>{{ post.body }}</p> </div> </div> </template> export { data () { return { loading: null } },created () { 组件创建完后获取数据, 此时 data 已经被 observed 了 .fetchData() },watch: { 如果路由有变化,会再次执行该方法 '$route': 'fetchData' },methods: { fetchData () { this.error = this.post = null this.loading = true replace getPost with your data fetching util / API wrapper getPost(this.$route.params.id,(err,post) =>false if (err) { this.error = err.toString() } else { this.post = post } }) } } }在导航完成前获取数据
通过这种方式,我们在导航转入新的路由前获取数据。我们可以在接下来的组件的
beforeRouteEnter
守卫中获取数据,当数据获取成功后只调用next
方法。export { post: { next(vm => vm.setData(err,post)) }) },1)"> 路由改变前,组件就已经渲染完了 逻辑稍稍不同 beforeRouteUpdate (to,1)"> getPost(to.params.id,1)">.setData(err,post) next() }) },methods: { setData (err,post) { (err) { err.toString() } post } } } }滚动行为
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。
vue-router
能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。注意: 这个功能只在支持
history.pushState
的浏览器中可用。当创建一个 Router 实例,你可以提供一个
scrollBehavior
方法:const router = VueRouter({ routes: [...],scrollBehavior (to,savedPosition) { return 期望滚动到哪个的位置 } })
scrollBehavior
方法接收to
和from
路由对象。第三个参数savedPosition
当且仅当popstate
导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。这个方法返回滚动位置的对象信息,长这样:
{ x: number,y: number }
{ selector: string,offset? : { x: number,y: number }}
(offset 只在 2.6.0+ 支持)如果返回一个 falsy (译者注:falsy 不是
false
,参考这里)的值,或者是一个空对象,那么不会发生滚动。举例:
scrollBehavior (to,savedPosition) { return { x: 0,y: 0 } }对于所有路由导航,简单地让页面滚动到顶部。
返回
savedPosition
,在按下 后退/前进 按钮时,就会像浏览器的原生表现那样:(savedPosition) { savedPosition } { } } }如果你要模拟『滚动到锚点』的行为:
(to.hash) { { selector: to.hash } } }