It has been 1060 days since the last update, the content of the article may be outdated.
vue-router
全称single page web application
整个应用只有一个完整的页面
点击页面的xx链接不会刷新页面 只会做局部更新
数据需要通过ajax请求获取
基本使用
下面以单页面多组件跳转为例子讲解router的基本使用
安装vuerouter
创建router文件夹 写入indexjs 并导入相关组件的地址和名字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import VueRouter from "vue-router";
import JOJO from '../components/JOJO.vue' import DIO from '../components/DIO.vue'
export default new VueRouter({ routes:[ { path:'/jojo', component:JOJO }, { path:'/dio', component:DIO } ] })
|
mainjs中导入以及应用
1 2 3 4 5 6 7 8 9 10 11
| import Vue from 'vue' import App from './App' import VueRouter from 'vue-router' import router from './router'
Vue.use(VueRouter) new Vue({ el:'#root', render:h=>h(App), router:router })
|
在app需要显示组件跳转的链接a标签改为
router-link
标签 并设置
to='/xxx地址'
可以自行添加
active-class
属性(前提是css里面有这个样式)跳转后实现效果
最后在要显示组件的地方 换成
<router-view></router-view>
标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <template> <div> <h1>开始学习router</h1> <hr /> <div class="middle"> <div class="navi"> <router-link to="/jojo" class="list-item" active-class="active">点我显示jojo组件</router-link> <router-link to="/dio" class="list-item" active-class="active">点我显示dio组件</router-link> </div> <div class="compon"> <router-view></router-view> </div> </div> </div> </template>
<script>
|
总结一图流

- 开发当中 被路由使用的组件叫做路由组件 其他的自己亲自注册亲自写的叫做一般组件
前者放在pages文件夹中 后者放在components文件夹中
- 被路由使用的组件 会在页面需要的时候挂载 不需要的时候销毁
- 每个路由器都有自己的
$route
属性 里面存着自己的路由信息
- 整个应用只有一个router 可以通过组件的
$router
属性获取
嵌套路由
嵌套路由为了解决组件中想继续显示子组件的问题 使用到了children配置项
定义好子组件
在路由中引入子组件 注意这里使用了children配置项 也是配置数组对象 且path不写斜杠
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
| import VueRouter from "vue-router";
import JOJO from '../pages/JOJO.vue' import DIO from '../pages/DIO.vue' import Msg from '../pages/Msg.vue' import News from '../pages/News.vue'
export default new VueRouter({ routes:[ { path:'/jojo', component:JOJO, children:[ { path:'msg', component:Msg }, { path:'news', component:News } ] }, { path:'/dio', component:DIO } ] })
|
引入在组件中引入子组件 注意routerlink标签要写对应的组件下子组件的地址
1 2 3 4 5 6 7 8 9 10 11
| <template> <div> <h1>bo ku wa jojo哒</h1> <ul class="jojotab"> <!-- 这里不是写/msg了 是写/组件/子组件 --> <li><router-link to="/jojo/msg" class="tabshow">Msg</router-link></li> <li><router-link to="/jojo/news" class="tabshow">News</router-link></li> </ul> <ul><router-view></router-view></ul> </div> </template>
|
注意的点 需要写routerview标签指定位置显示
路由的query参数
利用路由的query可以实现同个组件点击切换不同的内容
先定义好组件 这里是以messageList为例子 点击列表中的选项 下方显示出传递的内容

下方是组件Detail显示传递过来的信息 注意符号的使用
1 2 3 4 5 6
| <template> <ul> <li>消息id是:{{$route.query.id}}</li> <li>消息title是:{{$route.query.title}}</li> </ul> </template>
|
然后在路由的news下面导入以及定义detail
回到news 定义好列表 修改跳转的地址
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
| <template> <div> <ul> <li>老东西你的替身最强啦</li> <li v-for="m in messageList" :key="m.id"> <!-- 跳转路由并携带query参数 to的字符串写法--> <!-- <router-link :to="`/jojo/news/detail?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link> --> <!-- 跳转路由并携带query参数 to的对象写法--> <router-link :to="{ path: '/jojo/news/detail', query: { id: m.id, title: m.title, }, }" >{{ m.title }}</router-link > </li> </ul> <hr /> <router-view></router-view> </div> </template>
<script> export default { data() { return { messageList: [ { id: "001", title: "msg001" }, { id: "002", title: "msg002" }, { id: "003", title: "msg003" }, ], }; }, }; </script>
|
注意跳转路由携带query参数的写法 推荐第二种 比较清晰
必须注意绑定to
params参数和路由器的props配置
params参数接收基本和query相同 但是路径path要写成name
路由的props配置可以简化路由组件的编写
开启replace操作
编程式路由导航
不借助routerlink的路由导航就是编程式路由导航
如果要使用button或者其他非a标签进行跳转实现的时候,routerlink就没有作用了
以及定时器自动跳转(没有点击用不到a标签)
主要内容

push和replace部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <button @click="pushShow(m)">push</button> <button @click="replaceShow(m)">replace</button> ------------------------------------------------------------------------ methods: { pushShow(m) { this.$router.push({ path: "/jojo/news/detail", query: { id: m.id, title: m.title, }, }); }, replaceShow(m) { this.$router.replace({ path: "/jojo/news/detail", query: { id: m.id, title: m.title, }, }); }, },
|
前进后退和go部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <button @click="back">后退</button> <button @click="forward">前进</button> <button @click="testGo">测试一下go</button> ------------------------------------------------------------------------ methods: { back(){ this.$router.back(); }, forward(){ this.$router.forward(); }, testGo(){ // 正数前进 负数后退 this.$router.go(3) } },
|
总结一波流

路由缓存
为了解决当页面中输入了相关内容后进行跳转最后回去还保留内容的问题
原因是组件的切换会重新挂载和销毁
利用到keepalive标签以及include属性
msg里面定义输入框
1 2 3 4 5 6
| <template> <ul> <li>name:<input type="text"></li> <li>stand:<input type="text"></li> </ul> </template>
|
jojo里面 (使用到输入框的父组件)设置keepalive
1 2 3 4 5 6 7 8 9 10 11 12 13
| <template> <div> <h1>bo ku wa jojo哒</h1> <ul class="jojotab"> <!-- 这里不是写/msg了 是写/组件/子组件 --> <li><router-link to="/jojo/msg" class="tabshow">Msg</router-link></li> <li><router-link to="/jojo/news" class="tabshow">News</router-link></li> </ul> <keep-alive include="Msg"> <router-view></router-view> </keep-alive> </div> </template>
|
注意 keepalive包裹的是routerview标签
include属性是指定缓存哪个组件 不写的话默认全部
最后特别注意 使用到include的时候 对应的组件要设置name
1 2 3 4 5
| <script> export default { name:'Msg' }; </script>
|
总结一图流
补充说明
如果想缓存多个路由组件 使用到v-bind
和数组写法

两个新的生命周期钩子
如果使用上述的缓存路由就会出现一个问题 缓存组件中的东西没有执行销毁
引出两个路由的生命周期钩子 activated 和 deactivated
激活 activated
将之前需要写在mounted里面的功能写入 当切换到该组件就生效
失活 deactivated
将之前需要写在销毁之前的功能写入 当离开该组件生效
一图流

全局路由守卫
用于判断某些条件的执行是否满足才进入到路由的下一级
全局前置路由:每一次切换前都被调用
要用到全局路由守卫就必须接收路由再暴露出去
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
| const router = new VueRouter({ routes: [{ path: '/jojo', component: JOJO, children: [{ path: 'msg', component: Msg }, { path: 'news', component: News, children: [{ path: 'detail', component: Detail, props($route) { return { id: $route.query.id, title: $route.query.title }
} }] } ] }, { path: '/dio', component: DIO } ] }) router.beforeEach((to,from,next)=>{ console.log(to,from); if(to.path === '/jojo/news'){ next(); console.log('去往news'); }else{ next(); } }) export default router
|
用到了beforeEach的方法 值得一提的是三个参数
to代表的是去往的位置
from代表从哪里来
next代表是否执行下一步
example:先点击jojo 后点击dio 就出现to里面有dio from里面有jojo
对于to 和 from 两者携带的参数如下

其中name指的是路由的名字 这里没有定义所以是undefined
可以在meta里面放入个人定义的信息 这个属性称之为路由元信息
就不用逐个判断这么复杂了 只要路由守卫判断路由信息里面是否有存在这么个meta里面的属性 就可以执行或不执行下面的步骤
且注意没有定义的时候 就是undefined 自然为假 所以只用定义真的情况
此处在news里面设置meta
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
| const router = new VueRouter({ routes: [{ path: '/jojo', component: JOJO, children: [{ path: 'msg', component: Msg }, { path: 'news', component: News, children: [{ path: 'detail', component: Detail, props($route) { return { id: $route.query.id, title: $route.query.title }
} }], meta:{isAuth:true} } ] }, { path: '/dio', component: DIO } ] }) router.beforeEach((to,from,next)=>{ console.log(to,from); if(to.meta.isAuth){ next(); console.log('去往news'); }else{ next(); } }) export default router
|
全局后置守卫
没有next功能 常用于网页标题的切换
如果只使用前置守卫去切换这个标题的话 会出现一瞬间的网页标题错误等细节问题
所以使用后置守卫写比较好
另外修改标题的方法是
document.title = xxx
这里最好使用meta定义的title

总结一波流

独享路由守卫
如果只想对单个路由进行权限操作 则可以使用独享路由守卫来执行
beforeEnter 也有to from next三个参数 类似于beforeEach
但独享路由守卫只有前置路由守卫 没有后置
一图流:

组件路由守卫
history模式与hash模式
vue的路由有两种工作模式 hash 和 history 默认是hash
hash模式 地址栏井号斜杠后面的所有参数都是hash值 特点是不随http请求发给服务器
意味着如果后面写了很多东西 它也不会发给服务器的
history模式 没有井号 比较美观
默认hash模式 切换成history模式

此外 hash模式的兼容性比history好
且 如果项目上线的时候 打包为history模式 会在刷新的时候出现404问题 因为服务端没有配置相关地址 但hash 就不会 因为井号后面不会发给服务端
