vue-router

作者 likaiqiang 日期 2017-04-13
vue-router

start

这次使用vue-cli

vue init webpack vue-router

下载过程就不说了,名称,项目描述什么的自己填,最后的各种测试都选择no,vue-router也选择no(后面自己安装)

下载完后的目录结构

安装依赖

cd vue-router
npm i
npm i vue-router -D
npm run dev

项目启动后

打开app.vue,删掉img和hello组件。

配置vue-router

创建router.config.js

import Vue from 'vue'//引入vue
import Router from 'vue-router'//引入vue-router
import tab1 from './components/tab1.vue'//引入tab1
import tab2 from './components/tab2.vue'//引入tab2
Vue.use(Router)
let routes = [ //配置路由参数
{
path:'/tab1',
component:tab1
},
{
path:'/tab2',
component:tab2
}
]

export default new Router({//导出一个router实例
routes:routes
})

main.js

import Vue from 'vue'
import App from './App'

import router from './router.config.js'//引入路由配置文件

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
el: '#app',
template: '<App/>',
components: { App },
router //把路由配置导入vue
})

app组件

<template>
<div id="app">
<router-link to='/tab1'> go tab1</router-link>
<router-link to='/tab2'>go tab2</router-link>
<router-view></router-view>
</div>
</template>
......

打开浏览器

一个最简单的vue-router例子就完成啦。

动态路由匹配

动态路由匹配实际上就是通过传参的方式匹配同一个组件,从而显示不同的内容

更改router.config.js

import Vue from 'vue'
import Router from 'vue-router'
import tab1 from './components/tab1.vue'
import tab2 from './components/tab2.vue'
import user from './components/user.vue'//引入user组件
Vue.use(Router)
let routes = [
{
path:'/tab1',
component:tab1
},
{
path:'/tab2',
component:tab2
},
{
path:'/user/:username',//username参数
component:user
}
]

export default new Router({
routes:routes
})

user组件

<template>
<div>username:{{username}}</div>
</template>
<script>
export default {
data(){
return {
username:this.$route.params
}
},
watch:{
$route:function(to,from){
this.username = to.params
}
}
}
</script>

打开浏览器

浏览器地址栏手动传参

这种传参方式还可以传递查询字符串或者hash值

user.vue

......
watch:{
$route:function(to,from){
this.username = this.$route.params
console.log(to)//把当前的路由打印出来
}
}
.......

嵌套路由

嵌套路由顾名思义,就是路由中的路由,听起来有点绕,举个例子。

router.config.js

......
import tab3 from './components/tab3.vue'
import tab4 from './components/tab4.vue'
......
{
path:'/user/:username',
component:user,
children:[
{
path:'tab3',
component:tab3
},
{
path:'tab4',
component:tab4
}
]
}
......

user.vue

<template>
<div>
<div>username:{{username}}</div>
<p>
<router-link to="/user/1/tab3">user/tab3</router-link>
<router-link to="/user/1/tab4">user/tab4</router-link>
</p>
<router-view></router-view>
</div>
</template>

打开浏览器分别点击user/tab3、user/tab4可切换不同的内容,这就实现了一个简单的嵌套路由。

编程式导航

这是vue-router仿照浏览器的历史记录实现的一个路由“历史记录”,可以用代码控制路由的前进、后退、跳转功能。

来看一个例子:

router.config.js

......
{
path:'/user/:username/',
component:user,
name:'user',
children:[
{
path:'tab3',
component:tab3,
name:'tab3'
},
{
path:'tab4',
component:tab4,
name:'tab4'
}
]
}
......

为了方便操作,给每层嵌套的路由都起个名字

user.vue

<template>
<div>
<div>username:{{username}}</div>
<p>
<button @click="tab3">go tab3</button>
<button @click="tab4">go tab4</button>
</p>
<router-view></router-view>
</div>
</template>
......
methods:{
......
tab3(){
if(this.$route.name=='user'){
if(/\/$/.test(this.$route.path)){ //区分user/1/与user/1两种情况
this.$router.push({path:'tab3'})
}
else{
this.$router.push({path:`${this.username}/tab3`})
}
}
else{
if(this.$route.name=='tab3') return;
else {
this.$router.push({path:'tab3'})
//this.$router.replace({path:'tab3'})
}
}
},
tab4(){
if(this.$route.name=='user'){
if(/\/$/.test(this.$route.path)){
this.$router.push({path:'tab4'})
}
else{
this.$router.push({path:`${this.username}/tab4`})
}
}
else{
if(this.$route.name=='tab4') return;
else {
this.$router.push({path:'tab4'})
//this.$router.replace({path:'tab4'})
}
}
}
}

PS:这里注意this.$route和this.$router是两个完全不同的对象,二者仅仅相差一个字母。前者是当前的路由对象,包括当前路由的参数、查询字符串、hash等信息;而后者是一个vueRouter实例。

浏览器:

代码放在了github

自己改一下代码,把push改成replace体会一下区别

命名路由

命名路由就不说了,就是给路由起个名字方便操作而已。

命名视图

就是给视图起个名字,具体的可以参考文档上的例子

也可以看我github上的demo2

重定向和别名

重定向就是强制使一个路由跳转到另一个路由,最典型的用法就是让’/‘跳转到’/Home’,demo2中并没有配置’/‘的路由信息,我们让它强制跳转到’/Home’

router.config.js

{
path:'/',
redirect:'/Home'
}

别名就是给当前的路由起个名字,demo3中若要访问’/Home/foo’,可以直接访问他的别名,即/foo;若要访问’/Home/bar’,可以直接访问他的别名,即/Home/bar-alias。

导航钩子

全局钩子

可以注册一个全局的钩子函数,每个导航被调用时,都会触发这个钩子函数

main.js

......
import router from './router.config.js'

Vue.config.productionTip = false

router.beforeEach((to,from,next)=>{//进入某个导航前被调用,此时该导航还没有被调用
console.log(to)
console.log(from)
next()//必须调用next(),不然进入不了下一个导航,可以调用next(false)来中断当前导航或者next('/xxx')跳转到其他导航
})

router.afterEach((router)=>{//离开该导航时被调用
console.log(router)
})
......

PS:写到这里,突然有个疑问,不调用next()与调用next(false)有什么区别,留个问题在这。

某个路由独享的钩子

用法和全局钩子一样,区别是该钩子函数是某个路由独享的,只有该路由被调用时才会被使用。

组件内的钩子

beforeRouteEnter
beforeRouteUpdate (2.2 新增)
beforeRouteLeave

beforeRouteEnter

某个导航被调用后,相应的组件被调用前响应该钩子函数,不能访问组件的this,因为此时组件还没有被创建,我们来模拟一下这个过程。

demo3中router.config.js

......
{
path: 'foo/:id',
component: Foo,
alias: '/foo/:id',
beforeEnter:(to,from,next)=>{
console.log('foo:beforeEach')
next()
}
/*afterEnter:()=>{
console.log('foo:afterEach')
}*/
},
......

foo.vue

<template>
<div>
<div>foo</div>
<div>id:{{id}}</div>
</div>
</template>
<script>
export default {
beforeRouteEnter(to,from,next){
console.log('foo:beforeRouterEnter')
next()
},
beforeRouteUpdate(to,from,next){
console.log('foo:beforeRouterUpdate')
next()
},
beforeRouteLeave(to,from,next){
console.log('foo:beforeRouterLeave')
next()
},
data(){
return {
id:undefined
}
},
created(){
//console.log(this.$route)
this.id = this.$route.params.id
},
watch:{
$route:function(to,from){
this.id = to.params.id
}
}
}
</script>

浏览器访问 http://localhost:8080/#/foo/1

foo:beforeEach
foo:beforeRouterEnter

不要刷新浏览器,继续访问 http://localhost:8080/#/foo/2

foo:beforeRouterUpdate

继续访问 http://localhost:8080/#/home

foo:beforeRouterLeave

路由元信息

过渡效果

数据获取

滚动行为

懒加载

(未完,待续)