路由 — Vue.js
1.官方路由
对于大多数单页面应用,都推荐使用官方支持的 vue-router 库。
1.1 入门
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<router-view></router-view>
</div>
<script>
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
</script>
</body>
</html>
注意:如果组件包含install
方法,使用该组件时需要通过Vue.use(...)
显式声明。这里没有使用Vue.use(...)
,显然是跟引入的库的版本有关。
1.2 动态路由匹配
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/user/1">用户1</router-link>
<router-link to="/user/2">用户2</router-link>
</p>
<router-view></router-view>
</div>
<script>
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [
{path: '/user/:id', component: User}
]
})
const app = new Vue({
el: '#app',
router
})
</script>
</body>
</html>
注意到/user/:id
的:id
是动态的部分,我们通过$route.params
可以访问到这些动态的内容。
下面监听组件参数的变化。
const User = {
template: '<div>User {{ $route.params.id }}</div>',
watch: {
$route: function(to, from){
console.log(to, from);
}
}
}
/*
const User = {
template: '<div>User {{ $route.params.id }}</div>',
beforeRouteUpdate (to, from, next) {
console.log(to, from);
}
}
*/
1.3 嵌套路由
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/user/foo">/user/foo</router-link>
<router-link to="/user/foo/profile">/user/foo/profile</router-link>
<router-link to="/user/foo/posts">/user/foo/posts</router-link>
</p>
<router-view></router-view>
</div>
<script>
const User = {
template: `
<div class="user">
<h2>User {{ $route.params.id }}</h2>
<router-view></router-view>
</div>
`
}
const UserHome = { template: '<div>Home</div>' }
const UserProfile = { template: '<div>Profile</div>' }
const UserPosts = { template: '<div>Posts</div>' }
const router = new VueRouter({
routes: [
{path: '/user/:id', component: User,
children: [
{ path: '', component: UserHome },
{
path: 'profile',
component: UserProfile
},
{
path: 'posts',
component: UserPosts
}
]}
]
})
const app = new Vue({
el: '#app',
router
})
</script>
</body>
</html>
1.4 编程式导航
1.4.1 router.push(location, onComplete, onAbort)
<router-link :to="...">
等价于router.push(...)
。
router.push('home')
// /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })
const userId = '123'
router.push({ name: 'user', params: { userId } }) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// This will NOT work
router.push({ path: '/user', params: { userId } }) // -> /user
1.4.2 router.replace(location, onComplete, onAbort)
<router-link :to="..." replace>
等价于router.replace(...)
。
看一个例子。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<button @click="pushShow('/user/foo')">/user/foo</button>
<button @click="pushShow('/user/foo/profile')">/user/foo/profile</button>
<button @click="pushShow('/user/foo/posts')">/user/foo/posts</button>
<!--
<button @click="replaceShow('/user/foo')">/user/foo</button>
<button @click="replaceShow('/user/foo/profile')">/user/foo/profile</button>
<button @click="replaceShow('/user/foo/posts')">/user/foo/posts</button>
-->
<!-- <button @click="$router.back()">回退</button> -->
<button @click="goBack()">回退</button>
<!--
<router-link to="/user/foo">/user/foo</router-link>
<router-link to="/user/foo/profile">/user/foo/profile</router-link>
<router-link to="/user/foo/posts">/user/foo/posts</router-link>
-->
</p>
<router-view></router-view>
</div>
<script>
const User = {
template: `
<div class="user">
<h2>User {{ $route.params.id }}</h2>
<router-view></router-view>
</div>
`
}
const UserHome = { template: '<div>Home</div>' }
const UserProfile = { template: '<div>Profile</div>' }
const UserPosts = { template: '<div>Posts</div>' }
const router = new VueRouter({
routes: [
{path: '/user/:id', component: User,
children: [
{ path: '', component: UserHome },
{
path: 'profile',
component: UserProfile
},
{
path: 'posts',
component: UserPosts
}
]}
]
})
const app = new Vue({
el: '#app',
router,
methods: {
pushShow (id) {
if(id){
this.$router.push(id);
}
},
replaceShow (id) {
if(id){
this.$router.replace(id);
}
},
goBack () {
window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')
}
}
})
</script>
</body>
</html>
1.5 命名路由
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<!--
<button @click="pushShow({path: '/user/foo'})">/user/foo</button>
<button @click="pushShow({path: '/user/foo/profile'})">/user/foo/profile</button>
<button @click="pushShow({path: '/user/foo/posts'})">/user/foo/posts</button>
-->
<!--
<button @click="pushShow({name: 'user', params: {id: 'foo'}})">/user/foo</button>
<button @click="pushShow({name: 'uProfile', params: {id: 'foo'}})">/user/foo/profile</button>
<button @click="pushShow({name: 'uPosts', params: {id: 'foo'}})">/user/foo/posts</button>
-->
<router-link :to="{name: 'user', params: {id: 'foo'}}">/user/foo</router-link>
<router-link :to="{name: 'uProfile', params: {id: 'foo'}}">/user/foo/profile</router-link>
<router-link :to="{name: 'uPosts', params: {id: 'foo'}}">/user/foo/posts</router-link>
</p>
<router-view></router-view>
</div>
<script>
const User = {
template: `
<div class="user">
<h2>User {{ $route.params.id }}</h2>
<router-view></router-view>
</div>
`
}
const UserHome = { template: '<div>Home</div>' }
const UserProfile = { template: '<div>Profile</div>' }
const UserPosts = { template: '<div>Posts</div>' }
const router = new VueRouter({
routes: [
{path: '/user/:id', name: 'user', component: User,
children: [
{ path: '', component: UserHome },
{
path: 'profile',
name: 'uProfile',
component: UserProfile
},
{
path: 'posts',
name: 'uPosts',
component: UserPosts
}
]}
]
})
const app = new Vue({
el: '#app',
router,
methods: {
pushShow (id) {
if(id){
this.$router.push(id);
}
}
}
})
</script>
</body>
</html>
注意:如果父路由带动态参数,子路由就需要传params
,比如<router-link :to="{name: 'uProfile', params: {id: 'foo'}}">
。
1.6 命名视图
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo">Foo</router-link>
<router-link to="/other">Other</router-link>
</p>
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>
</div>
<script>
const Foo = { template: '<div>Foo</div>' }
const Bar = { template: '<div>Bar</div>' }
const Baz = { template: '<div>Baz</div>' }
const router = new VueRouter({
routes: [
{
path: '/foo',
components: {
default: Foo,
a: Bar,
b: Baz
}
},
{
path: '/other',
components: {
default: Baz,
a: Bar,
b: Foo
}
}
]
})
const app = new Vue({
el: '#app',
router
})
</script>
</body>
</html>
1.6.1 嵌套命名视图
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<router-view></router-view>
</div>
<script>
const FooSettings = {
template: `<div><router-link to="/foo/bar">Bar</router-link> <router-link to="/foo/baz">Baz</router-link></div>`
}
const Foo = {
template: `<div>Foo
<div><FooSettings/></div>
<router-view></router-view><router-view name="helper"></router-view></div>`,
components: { FooSettings }
}
const Bar = { template: '<div>Bar</div>' }
const Baz = { template: '<div>Baz</div>' }
const Baz1 = { template: '<div>Baz1</div>' }
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [{
path: 'bar',
component: Bar
}, {
path: 'baz',
components: {
default: Baz,
helper: Baz1
}
}]
}
]
})
router.push('/foo/bar')
const app = new Vue({
el: '#app',
router
})
</script>
</body>
</html>
1.7 重定向和别名
在1.1 入门的例子中,我们可以把路由改为:
const routes = [
{ path: '', redirect: '/bar' },
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
这样页面就会重定向到路由/bar
。
我们也可以在重定向中使用命名路由。
const routes = [
{ path: '', redirect: {name: 'foo'} },
{ path: '/foo', component: Foo, name: 'foo' },
{ path: '/bar', component: Bar, name: 'bar' }
]
通过alias
我们可以给路由起别名。重定向路由访问地址会发生改变,而路由别名意味着访问地址不会发生改变,但是使用path
和alias
声明的路由访问的是同一个东西。
const routes = [
{ path: '/foo', component: Foo, alias: '/abc' },
{ path: '/bar', component: Bar, alias: '/def' }
]
提示:这里alias
我没有试成功,不知道是不是 vue-router 版本的问题。
1.8 传递props到路由组件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo/123">Go to Foo</router-link>
</p>
<router-view></router-view>
</div>
<script>
const Foo = { template: '<div>foo {{ $route.params.id }}</div>' }
const routes = [
{ path: '/foo/:id', component: Foo }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
</script>
</body>
</html>
为了解耦组件和路由器,我们可以把JS改写成:
const Foo = { props: ['id'], template: '<div>foo {{ id }}</div>' }
const routes = [
{ path: '/foo/:id', component: Foo, props: true }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.router-link-active {
color: red;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/dynamic/2">DynamicPropsFunction</router-link>
</p>
<router-view></router-view>
</div>
<script>
function dynamicPropsFn (route) {
const now = new Date()
return {
name: (now.getFullYear() + parseInt(route.params.years)) + '!'
}
}
const Foo = { props: { name: {type: String, default: 'Vue!'} }, template: '<div>foo {{ name }}</div>' }
const routes = [
{ path: '/foo', component: Foo, props: {name: 'bar'} },
{ path: '/dynamic/:years', component: Foo, props: dynamicPropsFn }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
</script>
</body>
</html>
路由中的props
可以设置为布尔值、对象甚至是函数。
参考: