【1】路由入门
官网文档:https://router.vuejs.org/zh/installation.html
github: https://github.com/vuejs/vue-router
① 基础入门
① 下载安装
npm install vue-router --save
② 引入模块
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)
③ 创建router 模块
index.js如下所示
/* 路由器对象模块 */ import Vue from 'vue' import VueRouter from 'vue-router' import About from '../pages/About.vue' import Home from '../pages/Home.vue' // 声明使用vue-router插件 /* 内部定义并注册了2个组件标签(router-link/router-view), 给组件对象添加了2个属性: 1. $router: 路由器 2. $route: 当前路由 */ Vue.use(VueRouter) export default new VueRouter ({ // 注册应用中所有的路由 routes: [ { path: '/about', component: About }, { path: '/home', component: Home, }, {//根路由 path: '/', redirect: '/about' } ] })
上面代码也可改写为如下方式:
/*路由器对象模块 */ import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) const routes = [ { path: '/about', name: "About", component: () =>import(/* webpackChunkName: "About" */ "../pages/About.vue") }, { path: '/home', name:'Home', component: () =>import(/* webpackChunkName: "Home" */ "../pages/Home.vue"), }, {//根路由 path: '/', redirect: '/about' } ]; const router = new VueRouter({ mode: "history", routes }); export default router;
还可以指定绝对路径,如下所示:
//声明组件 import filmSchedule from '@/views/modules/filmSchedule/list' //定义路由 { path: '/filmSchedule', name: '电影排片', component: filmSchedule },
④ 入口js-main.js中配置路由组件
/* 入口JS */ import Vue from 'vue' import App from './App.vue' import router from './router' /*配置对象的属性名称都是确定的名称 ,不能随便修改 */ new Vue({ el: '#app', components: {App}, // 映射组件标签 template: '<App/>', // 指定需要渲染到页面的模板 router // 注册路由器 })
⑤ 页面
<div class="list-group"> <!--生成路由链接--> <router-link to="/about" class="list-group-item">About</router-link> <router-link to="/home" class="list-group-item">Home</router-link> </div> <div class="panel-body"> <!--显示当前组件--> <keep-alive> <router-view msg="abc"></router-view> </keep-alive> </div>
② 重定向和别名
重定向也是通过 routes 配置来完成,下面例子是从 /a
重定向到 /b
:
const router = new VueRouter({ routes: [ { path: '/a', redirect: '/b' } ] })
重定向的目标也可以是一个命名的路由:
const router = new VueRouter({ routes: [ { path: '/a', redirect: { name: 'foo' }} ] })
甚至是一个方法,动态返回重定向目标:
const router = new VueRouter({ routes: [ { path: '/a', redirect: to => { // 方法接收 目标路由 作为参数 // return 重定向的 字符串路径/路径对象 }} ] })
注意导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在下面这个例子中,为 /a 路由添加一个 beforeEnter 守卫并不会有任何效果。
别名
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,那么“别名”又是什么呢?
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
上面对应的路由配置为:
const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] })
“别名”的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。
③ 命名路由
有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。
const router = new VueRouter({ routes: [ { path: '/user/:userId', name: 'user', component: User } ] })
要链接到一个命名路由,可以给 router-link
的 to
属性传一个对象:
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
这跟代码调用 router.push()
是一回事:
router.push({ name: 'user', params: { userId: 123 } })
这两种方式都会把路由导航到 /user/123
路径。
【2】嵌套路由
路由模块的index.js
/* 路由器对象模块 */ import Vue from 'vue' import VueRouter from 'vue-router' import About from '../pages/About.vue' import Home from '../pages/Home.vue' import News from '../pages/News.vue' import Message from '../pages/Message.vue' import MessageDetail from '../pages/MessageDetail.vue' // 声明使用vue-router插件 Vue.use(VueRouter) export default new VueRouter ({ // 注册应用中所有的路由 routes: [ { path: '/about', component: About }, { path: '/home', component: Home, children: [ { path: '/home/news',//path最左侧/代表根路径 component: News }, { path: 'message',//这里没有用/ 表示相对路径 component: Message, children: [ { path:'detail/:id', component: MessageDetail } ] }, { path: '', redirect: '/home/news' } ] }, { path: '/', redirect: '/about' } ] })
页面
<template> <div> <h2>Home</h2> <div> <ul class="nav nav-tabs"> <li><router-link to="/home/news">News</router-link></li> <li><router-link to="/home/message">Message</router-link></li> </ul> <router-view></router-view> </div> </div> </template>
【3】缓存路由组件对象
默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的。如果可以缓存路由组件对象, 可以提高用户体验。
可以使用标签keep-alive
将router-view
包含,这样被访问过的路由就会保持生存。
<keep-alive> <router-view></router-view> </keep-alive>
【4】向路由组件传递数据
① 路由路径携带参数(param/query)
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内使用。
配置路由
{ path: 'message', component: Message, children: [ { path:'detail/:id', component: MessageDetail } ] }
页面
<ul> <li v-for="m in messages" :key="m.id"> //这里是ES6语法,ES5语法为'' <router-link :to="`/home/message/detail/${m.id}`">{{m.title}}</router-link> </li> </ul>
如上所示即可通过URL传递id到路由。路由组件中读取请求参数this.$route.params.id
。为什么不是this.$route.query.id
呢?是因为这里没有使用?id=XX
这种传参方式。
<script> export default { data() { return { detail: {} } }, // 改变当前路由组件参数数据时, 不会重新创建组件对象, mounted不会重新执行 mounted () { const id = this.$route.params.id this.detail = messageDetails.find(detail => detail.id===id*1) }, watch: { $route: function () { // 改变当前路由组件参数数据时自动调用 const id = this.$route.params.id this.detail = messageDetails.find(detail => detail.id===id*1) } } } </script>
更多实例:
//两种正确写法 router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 这里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user //当前页面 this.$router.push(`concertDetail?concertId=${id}`) this.$router.push({ path: 'concertDetail', query: { "concertId": id } }) //concertDetail页面获取参数 this.$route.query.concertId
② <router-view>属性携带数据
页面如下所示:
<keep-alive> <router-view msg="abc"></router-view> </keep-alive>
在路由模板页面可取到msg:
<template> <div> <h2>About</h2> <p>{{msg}}</p> <input type="text"> </div> </template> <script> export default { props: { msg: String } } </script>
【5】编程式路由导航
① router.push
除了使用 <router-link>
创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
router.push(location, onComplete?, onAbort?)
注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push。
想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
当你点击 <router-link>
时,这个方法会在内部调用,所以说,点击 <router-link :to="...">
等同于调用 router.push(...)
。
声明式 | 编程式 |
<router-link :to="..."> |
router.push(...) |
该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:
// 字符串 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', params: { userId }}) // -> /user
同样的规则也适用于 router-link 组件的 to 属性。
在 2.2.0+,可选的在 router.push 或 router.replace 中提供 onComplete 和 onAbort 回调作为第二个和第三个参数。这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用。在 3.1.0+,可以省略第二个和第三个参数,此时如果支持 Promise,router.push 或 router.replace 将返回一个 Promise。
注意: 如果目的地和当前路由相同,只有参数发生了改变 (比如从一个用户资料到另一个 /users/1 -> /users/2),你需要使用 beforeRouteUpdate 来响应这个变化 (比如抓取用户信息)。
② router.replace
router.replace(location, onComplete?, onAbort?)
跟 router.push
很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
声明式 | 编程式 |
<router-link :to="..." replace> |
router.replace(...) |
使用实例如下:
<li v-for="m in messages" :key="m.id"> <router-link :to="`/home/message/detail/${m.id}`">{{m.title}}</router-link> <button @click="pushShow(m.id)">push查看</button> <button @click="replaceShow(m.id)">replace查看</button> </li> methods: { pushShow (id) { this.$router.push(`/home/message/detail/${id}`) }, replaceShow(id) { this.$router.replace(`/home/message/detail/${id}`) } }
总结如下:
1) this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面) 2) this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面) 3) this.$router.back(): 请求(返回)上一个记录路由 4) this.$router.go(-1): 请求(返回)上一个记录路由 5) this.$router.go(1): 请求下一个记录路由
③ 替换路由参数并刷新路由
this.$router.replace({ name: 'concertDetail', query: { concertId: id } }) /** 兼容性好*/ window.location.reload()