1.环境安装
1 2 3
| "@vue/cli": "4.5.9" "vue": "^2.6.11", "vue-router": "^3.4.9"
|
1 2 3
| npm i @vue/cli # 安装完脚手架后可以根据cli进行项目创建,并在创建项目过程中选择vue和vue-router的安装 npm i vue-router --save # 也可手动安装vue-router
|
2.基础使用
2.1安装VueRouter
1.npm install vue-router –save
2.新建src/router/index.js
3.在index.js中为Vue安装路由功能,并导出需要的VueRouter
4.在main.js中引入VueRouter实例
5.将VueRouter实例对象挂载到Vue实例中
index.js
1 2 3 4 5 6 7 8
| import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)
export default new VueRouter({ routes: [] })
|
main.js
1 2 3 4 5 6 7 8 9 10 11 12 13
| import Vue from 'vue' import App from './App.vue' import router from './router'
Vue.config.productionTip = false
new Vue({ render: h => h(App), router, }).$mount('#app')
|
2.2配置VueRouter
新建两个组件Home.vue,About.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <!-- Home.vue --> <template> <div> <h1>首页</h1> <div>这是首页内容</div> </div> </template>
<script> export default { name: "Home" } </script>
<style scoped>
</style> ----------------------------------------------- <!-- About.vue --> <template> <div> <h1>关于</h1> <div>这是关于我的相关信息</div> </div> </template>
<script> export default { name: "About" } </script>
<style scoped>
</style>
|
配置路由映射: 组件和路径映射关系
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import Vue from 'vue' import VueRouter from 'vue-router'
import Home from "@/components/Home"; import About from "@/components/About";
Vue.use(VueRouter)
export default new VueRouter({ routes: [ { path: '/home', name: 'home', component: Home }, { path: '/about', name: 'about', component: About } ] })
|
2.3.使用VueRouter
在Vue实例组件中的template使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <template> <div id="app"> <h1>Jelly's Website</h1> <!-- 使用 router-link 组件来导航. --> <!-- 通过传入 `to` 属性指定链接. --> <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --> <!-- tag: tag可以指定<router-link>之后渲染成什么组件,如 tag="button" --> <!-- 当router-link标签被点击激活后,该标签会自动添加上一个两个class --> <!-- 其中router-link-active可用于为激活的标签设定指定样式 --> <router-link to="/home">首页</router-link> <router-link to="/about">关于</router-link>
<!-- 路由出口 --> <!-- 路由匹配到的组件将动态渲染在这里 --> <router-view></router-view>
<div>@2020 by Jelly</div> </div> </template>
<script>
export default { name: 'App', components: {
} } </script>
<style>
</style>
|
2.4渲染结果


需要注意的是,当访问localhost:8080/ 根路径时,是没有视图渲染在router-view中的,可以手动为根路径配置路由重定向到所渲染的视图。
如下:
1 2 3
| const routes = [ {path: '/', redirect: '/home'} ]
|
2.5使用javascript方式跳转
有时候, 页面的跳转可能需要执行对应的JavaScript代码, 这个时候不用<router-link>
这种方式, 可以使用javascript跳转方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <template> <div id="app"> <h1>Jelly's Website</h1> <!-- 使用 router-link 组件来导航. --> <!-- 通过传入 `to` 属性指定链接. --> <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --> <router-link to="/home">首页</router-link> <router-link to="/about">关于</router-link> <br/>
<!-- 路由出口 --> <!-- 路由匹配到的组件将动态渲染在这里 --> <router-view></router-view>
<!-- javascript方式的路由跳转 --> <button @click="linkToHome">Home</button> <button @click="linkToAbout">About</button>
<div>@2020 by Jelly</div> </div> </template>
<script>
export default { name: 'App', methods: { linkToHome(){ this.$router.push('/home') //栈结构,可以通过back()跳转返回 }, linkToAbout(){ this.$router.replace('/about') //替代,无法跳转返回 }, //es6的语法格式,此处无法使用,this中无router //linkToAbout: ()=>this.$router.replace('/about') //替代,无法跳转返回 } } </script>
<style>
</style>
|
运行结果:

2.6路径url改变的两种方式
- 通过
location.hash = 'newURL'
来改变当前页面的url但不发生跳转
- 通过
history.pushState({},'','/newURL)
方式改变,更多使用方式不在次列举

分别执行上图两条语句后,页面url相应变成 http://localhost:8080/about#/home
和http://localhost:8080/about
但是不发生跳转,前者会拼接上一个锚点#,后者是Html5的history模式
默认vue-router使用的是hash锚点的方式,可以在配置文件中更改为history的方式。如下
1 2 3 4 5 6 7 8 9 10 11 12
| import Vue from 'vue' import VueRouter from 'vue-router'
Vue.use(VueRouter)
export default new VueRouter({ routes: [ ], mode: 'history' })
|
2.7动态路由匹配
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User
组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router
的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:
1 2 3 4 5 6 7 8 9 10
| const User = { template: '<div>User</div>' }
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User } ] })
|
现在呢,像 /user/foo
和 /user/bar
都将映射到相同的路由。
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内使用。于是,我们可以更新 User
的模板,输出当前用户的 ID:
1 2 3 4
| const User = { template: '<div>User {{ $route.params.id }}</div>' }
|
更详细的内容见官网
3.进阶使用
3.1懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块。只有在这个路由被访问到的时候, 才加载对应的组件
结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。
结合二者后的使用如下:
1 2 3 4 5 6 7 8
| const Home = () => import('../components/Home')
const router = new VueRouter({ routes: [ {path: '/home',name: 'home',component: Home}, ] })
|
3.2嵌套路由
为/home 嵌套如下两个route,/home/dashboard以及/home/log
新建两个组件DashBoard.vue、Log.vue以及Home.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <!-- DashBoard.vue --> <template> <div> 这是控制面板 </div> </template>
<script> export default { name: "DashBoard" } </script>
<style scoped>
</style>
<!-- Log.vue --> <template> <div> 这是日志记录 </div> </template>
<script> export default { name: "Log" } </script>
<style scoped>
</style>
<!-- 并更改Home.vue为 --> <template> <div> <h1>首页</h1> <div>这是首页内容</div> <!-- 首页内容嵌套路由的内容 --> <router-link to="/home/dashboard">控制面板</router-link> <router-link to="/home/log">日志记录</router-link> <router-view></router-view> </div> </template>
<script>
export default { name: "Home" } </script>
<style scoped>
</style>
|
在index.js的router中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import Vue from 'vue' import VueRouter from 'vue-router'
const Home = () => import('../components/Home') const About = () => import('../components/About')
Vue.use(VueRouter)
export default new VueRouter({ routes: [ {path: '',redirect: '/home'}, { path: '/home', name: 'home', component: Home, children: [ {path: 'dashboard', component: ()=>import('../components/DashBoard')}, {path: 'log', component: ()=>import('../components/Log')}, {path: '',redirect: 'dashboard'}, ] }, { path: '/about', name: 'about', component: About } ], mode: 'history' })
|
3.3参数传递
参数传递的方式:
params:对应restful风格URL获取参数,例如/user/:id
可通过$route.params.id访问,这点在2.7动态路由中已经展示。
query:对应传统Get方式获取请求参数,例如/user?id=1
可通过v-bind为route-link中的to属性绑定一个对象{path:’url-path’, query: {name: Jelly, age: 18} }
之后可以适应$route.query.name访问
最新的vue-router不使用$route.query,而使用耦合度更低的props
现就query方式的编写主要代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <!-- app.vue中使用路由 --> <router-link v-bind:to="{path:'/profile', query:{name:'Jelly' ,age: 18}}">我的信息</router-link> <router-view></router-view>
<!-- index.js配置路由 --> <script> routes: [ { path: '/profile', name: 'profile', component: ()=> import('../components/Profile') } </script>
<!-- prifile.vue --> <template> <div> <h1>我的信息</h1> <div>{{$route.query.name}}</div> <div>{{$route.query.age}}</div> </div> </template>
|
于2.5类似的,也可使用javascript的方式进行配置路由
在对应的methods中的点击监听函数写入:
this.$router.push({path: 'profile'}, query: {name:Jelly,age:18} })
即可
在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route ,并且当路由切换时,路由对象会被更新。
3.4导航守卫
vue-router提供的导航守卫主要用来监听监听路由的进入和离开的。vue-router提供了beforeEach和afterEach等的钩子函数, 它们会在路由即将改变前和改变后触发。简言之,就是在路由的改变过程中添加的回调函数,
供开发者自行实现。
守卫中的this.name
3.4.1全局守卫
全局前置守卫:
1 2 3 4 5 6
| router.beforeEach((to,from,next)=>{ alert("全局前置守卫:从"+from.path+"跳转到"+to.path) next() })
|
全局解析守卫:(实际上应该叫解析前守卫,因为是在目标组件解析前调用的)
在 2.5.0+ 你可以用 router.beforeResolve
注册一个全局守卫。这和 router.beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后(此时还没解析需要跳转的目标组件),解析守卫就被调用。具体所有钩子的调用顺序在后文中会详细提及。
1 2 3 4
| router.beforeResolve(((to, from, next) => { alert("全局解析守卫:从"+from.path+"跳转到"+to.path) next() }))
|
全局后置守卫:
1 2 3 4
| router.afterEach((to, from) => { alert("全局后置守卫:从"+from.path+"跳转到"+to.path) })
|
3.4.2局部守卫
路由独享的守卫:
1 2 3 4 5 6 7 8 9 10
| { path: '/about', name: 'about', component: About, beforeEnter: (to, from, next) => { alert("路由/about的独享守卫"+"从"+from.path+"到"+to.path) next() } },
|
组件内的守卫:
可以在路由组件内直接定义以下路由导航守卫:
beforeRouteEnter
beforeRouteUpdate (2.2 新增)
beforeRouteLeave
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| //以路由/About为例 <template> <div> <h1>关于</h1> <div>这是关于我的相关信息</div> </div> </template>
<script> export default { name: "About", /* beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。 不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。 next(vm => { // 通过 `vm` 访问组件实例 }) */ beforeRouteEnter (to, from, next) { alert("组件内的守卫:进入"+to.path+'前') // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 next() }, beforeRouteUpdate (to, from, next) { //此处并无演示
// 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` next() }, /*这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。*/ beforeRouteLeave (to, from, next) {
alert("组件内的守卫:离开"+from.path+'前') // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` next() } } </script>
<style scoped>
</style>
|
3.3守卫执行顺序
下方实例:
1.访问根目录,执行全局前置守卫

2.渲染其它异步组件(此处是个人理解),然后执行全局解析守卫

3.执行全局后置守卫

4.解析渲染目标组件

5.紧接着点击访问About路由,查看其它守卫的执行顺序






由此即可大致看出,导航守卫的大致执行过程;此处官网详细的执行顺序;
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。
- 调用全局的
beforeEach
守卫。
- 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。
- 在路由配置里调用
beforeEnter
。
- 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。
- 调用全局的
beforeResolve
守卫 (2.5+)。
- 导航被确认。
- 调用全局的
afterEach
钩子。
- 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给 next
的回调函数,创建好的组件实例会作为回调函数的参数传入。
关系导航守卫的更详细信息
3.5keep-alive
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
这就牵扯到了Vue实例的生命周期,created()函数 和 destroyed()函数,
当一个组件创建的时候,会调用created()函数,当一个组件消亡的时候,会调用 destroyed()函数。
当我们使用 的时候,当我们来回切换组件时,组件并不会被destroy,它会被缓存下来,以备下次调用。
当一个组件处于 <keep-alive>
的状态的时候,它就可以使用 activated()
和 deactivated()
这两个函数,表示组件被激活或失活时的钩子函数
keep-alive
有两个非常重要的属性。
include : 字符串或正则表达,只有匹配的组件会被缓存。
exclude : 字符串或正则表达式,任何匹配的组件都不会被缓存。