# VueRouter
Router
路由简介
路由与路由器
- vue-router: vue 的一个插件库,专门用来实现 SPA 应用

单页面
- 单页 Web 应用(single page web application,SPA)
- 整个应用只有一个完整的页面。
- 点击页面中的导航链接不会刷新页面,只会做页面的局部更新
- 数据需要通过 ajax 请求获取。

路由的工作流程

什么是路由
路由的分类
- 后端路由:
- 理解: value 是 function,用于处理客户端提交的请求。
- 工作过程: 服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据。
- 前端路由:
- 理解: value 是 component,用于展示页面内容。
- 工作过程: 当浏览器的路径改变时,对应的组件就会显示。
路由的基本使用
1 2 3
| npm i vue-router@3 # vue-router 3.x 版本只能在 vue2 中使用,若不指定版本安装,会安装最新版 vue-router 4.X,在vue 2.x 中使用会报错 # vue-router 4.x 版本是能在 vue3 中使用
|
- 02 导入并应用路由
- 04 导入路由配置信息
- 05 注册路由
main.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import Vue from 'vue' import App from './App.vue'
import VueRouter from "vue-router"
import router from "./router/index.js"
Vue.config.productionTip = false
Vue.use(VueRouter)
new Vue({ render: h => h(App), router, }).$mount('#app')
|
./src/router/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 24
|
import VueRouter from "vue-router";
import About from "../pages/About.vue"; import Home from "../pages/Home.vue";
export default new VueRouter({ routes: [ { path: "/about", component: About, }, { path: "/home", component: Home, }, ], });
|
1 2 3 4 5 6 7 8 9
| <div class="list-group">
<router-link class="list-group-item" active-class="active" to="/about">About</router-link> <router-link class="list-group-item" active-class="active" to="/home">Home</router-link> </div>
|
1 2 3 4
| <div class="panel-body"> <router-view></router-view> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <template> <div> <h1>我是About的内容</h1> </div> </template> <script> export default { name:"About", //组件进行切换时,会进行销毁和创建 beforeDestroy() { console.log("About组件即将被销毁~~~"); }, mounted() { console.log("About组件挂载完毕~~"); }, } </script> <style scoped lang = "less"> </style>
|
- 08 几个注意点
- 1.路由组件通常存放在 pages 文件夹,一般组件通常存放在 components 文件夹。
- 2.通过切换,“隐藏””了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
- 3.每个组件都有自己的 $route 属性,里面存储着自己的路由信息。
- 4.整个应用只有一个 router,可以通过组件的 $router 属性获取到。
多级路由的嵌套
- 01 在 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
| <template> <div> <div> <h2>Home组件内容</h2> <div> <ul class="nav nav-tabs"> <li> <router-link class="list-group-item" active-class="active" to="/home/news" >News</router-link > </li> <li> <router-link class="list-group-item" active-class="active" to="/home/message" >Message</router-link > </li> </ul> <router-view></router-view> </div> </div> </div> </template>
<script> export default { name: "Home", }; </script>
<style scoped lang="less"></style>
|
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
|
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"
export default new VueRouter({ routes: [ { path: "/about", component: About, }, { path: "/home", component: Home, children: [ { path: "news", component:News }, { path: "message", component:Message }, ] }, ], });
|
- 03 两个子路由文件 News.vue 和 Message.vue :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <div> <ul> <li>news001</li> <li>news002</li> <li>news003</li> </ul> </div> </template>
<script> export default { name: "News", components: {}, }; </script>
<style scoped lang="less"></style>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <div> <ul> <li><a href="/message1">message001</a> </li> <li><a href="/message2">message002</a> </li> <li><a href="/message/3">message003</a> </li> </ul> </div> </template>
<script> export default { name:"Message", components: {}, }; </script>
<style scoped lang="less"></style>
|
路由的query参数
- 01 新建 Detail.vue 路由组件:
- 04 在组件中获取 query 参数: [this.]$route.query.xxx
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <div> <ul> <li>消息编号:{{$route.query.id}}</li> <li>消息标题:{{$route.query.title}}</li> </ul> </div> </template> <script> export default { name:"Detail", } </script>
|
- 02 在 ./src/router/index.js 中配置路由信息,将 Detail.vue 组件配置成 Message.vue 的子路由
1
| import Detail from "../pages/Detail.vue";
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| { path: "/home", component: Home, children: [ { path: "news", component: News, }, { path: "message", component: Message, children: [ { path: "detail", component: Detail, }, ], }, ], },
|
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
| <template> <div> <ul>
<li v-for="m in messageList" :key="m.id"> <router-link :to="{ path: '/home/message/detail', query: { id: m.id, title: m.title, }, }" >{{ m.title }}</router-link > </li> </ul> <hr /> <router-view></router-view> </div> </template>
|
命名路由
- 01 在 ./src/router/index.js 中配置路由信息中添加 name 属性:
1 2 3 4 5 6 7 8 9 10 11
| { path: "message", component: Message, children: [ { name:"xiangqing", path: "detail", component: Detail, }, ], },
|
- 02 在 Message.vue 组件中进行路由跳转时,使用 name 命名路由
1 2 3 4 5 6 7 8 9 10 11 12 13
| <li v-for="m in messageList" :key="m.id"> <router-link :to="{ name: 'xiangqing', query: { id: m.id, title: m.title, }, }" >{{ m.title }}</router-link > </li>
|
- 03 同理在 路由配置信息中配置了 name 属性,在 router-link 标签中也可以使用命名路由进行路由跳转
1 2 3
| <router-link class="list-group-item" active-class="active" :to="{name:'guanyu'}">About</router-link> <router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
|
params参数
- 01 在 ./src/router/index.js 中配置路由信息的 path 中进行参数占位
1 2 3 4 5 6 7 8 9 10 11
| { path: "message", component: Message, children: [ { name:"xiangqing", path: "detail/:id/:title", component: Detail, }, ], },
|
- 02 在 Message.vue 路由组件中进行路由传参跳转
- 特别注意:路由携带 params 参数时,若使用 to 的对象写法,则不能使用 path 配置项,必须使用 name 配置!
1 2 3 4 5 6 7
| <li v-for="m in messageList" :key="m.id"> <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{ m.title }}</router-link > </li>
|
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
| <template> <div> <ul> <!-- 跳转路由并携带query参数,to的对象写法 --> <li v-for="m in messageList" :key="m.id"> <router-link :to="{ name: 'xiangqing', //若使用to的对象写法,用params进行路由传参,必须使用name命名路由进行跳转 params: { id: m.id, title: m.title, }, }" >{{ m.title }}</router-link > </li> </ul> <hr /> <router-view></router-view> </div> </template>
<script> export default { name: "Message", components: {}, data() { return { messageList: [ { id: "001", title: "消息001" }, { id: "002", title: "消息002" }, { id: "003", title: "消息003" }, ], }; }, }; </script>
|
- 03 在 Detail.vue 组件中获取 params 参数: [this.]$route.params.xxx
1 2 3 4 5 6 7 8
| <template> <div> <ul> <li>消息编号:{{$route.params.id}}</li> <li>消息标题:{{$route.params.title}}</li> </ul> </div> </template>
|
路由的props配置01
01 在 ./src/router/index.js 中配置路由信息中配置 props
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| { path: "/home", component: Home, children: [ { path: "news", component: News, }, { path: "message", component: Message, children: [ { name:"xiangqing", path: "detail/:id/:title", component: Detail, props: {id:1,title:"hello"} }, ], }, ], },
|
02 在 Detail.vue 组件中获取 props 参数,并使用
1 2 3 4 5 6 7 8
| <template> <div> <ul> <h1>{{id}}</h1> <h1>{{title}}</h1> </ul> </div> </template>
|
路由的props配置02
01 在 ./src/router/index.js 中配置路由信息中配置props
1 2 3 4 5 6 7 8 9 10 11 12 13
| { path: "message", component: Message, children: [ { name:"xiangqing", path: "detail/:id/:title", component: Detail, props:true }, ], },
|
02 在 Detail.vue 组件中获取 props 参数,并使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div> <ul> <h1>{{id}}</h1> <h1>{{title}}</h1> </ul> </div> </template> <script> export default { props:["id","title"], name:"Detail", } </script>
|
路由的props配置03
01 在 Message.vue 组件中,跳转路由并携带 query 参数
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
| <template> <div> <ul> <li v-for="m in messageList" :key="m.id"> <router-link :to="{ name: 'xiangqing', //若使用to的对象写法,用params进行路由传参,必须使用name命名路由进行跳转 query: { id: m.id, title: m.title, }, }" >{{ m.title }}</router-link > </li> </ul> <hr /> <router-view></router-view> </div> </template>
<script> export default { name: "Message", components: {}, data() { return { messageList: [ { id: "001", title: "消息001" }, { id: "002", title: "消息002" }, { id: "003", title: "消息003" }, ], }; }, }; </script>
|
02 在 ./src/router/index.js 中配置路由信息中配置 props
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| { path: "message", component: Message, children: [ { name: "xiangqing", path: "detail/:id/:title", component: Detail,
props($route) { return { id: $route.query.id, title: $route.query.title }; }, }, ], },
|
03 在 Detail.vue 组件中获取 props 参数,并使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div> <ul> <h1>{{id}}</h1> <h1>{{title}}</h1> </ul> </div> </template> <script> export default { props:["id","title"], name:"Detail", } </script>
|
routerLink的replace
1.作用: 控制路由跳转时操作浏览器历史记录的模式
⒉浏览器的历史记录有两种写入方式:分别为 push 和 replace, push 是追加历史记录,replace 是替换当前记录。路由跳转时候默认为 push
3.如何开启 replace 模式: <router-link replace .... . .. >News</router-link>
1 2 3 4 5
| <div class="list-group"> <router-link replace class="list-group-item" active-class="active" :to="{name:'guanyu'}">About</router-link> <router-link replace class="list-group-item" active-class="active" to="/home">Home</router-link> </div>
|
编程式路由导航
- 作用:不借助
<router-link>实现路由跳转,让路由跳转更加灵活
Message.vue:
1 2
| <button @click="pushShow(m)">push查看</button> <button @click="replaceShow(m)">replace查看</button>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| methods: { pushShow(m) { this.$router.push({ name:"xiangqing", params: { id: m.id, title: m.title, }, }); }, replaceShow(m){ this.$router.replace({ name:"xiangqing", params: { id: m.id, title: m.title, }, }); } },
|
banner.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
| <template> <div class="col-xs-offset-2 col-xs-8"> <div class="page-header"> <h2>Vue Router Demo</h2> <button @click="back">后退</button> <button @click="forward">前进</button> <button @click="test">测试一下go</button> </div> </div> </template>
<script> export default { name:'Banner', methods: { back(){ this.$router.back()//后退一 }, forward(){ this.$router.forward()//前进一 }, test(){ this.$router.go(3)//可以前进可以后退 } }, } </script>
|
缓存路由组件
01 添加 keep-live 组件包裹 router-view 组件即可,被缓存的组件不会被销毁(不会调用 beforeDestroy(){} 方法)
02 不添加 include 属性,则会缓存所有在这里显示的路由组件
03 添加 include 属性,则被指定的路由组件才会被缓存,属性值为组件的 name 属性值
1 2 3
| <keep-alive include="News"> <router-view></router-view> </keep-alive>
|
1 2 3
| <keep-alive :include="['News','Message']"> <router-view></router-view> </keep-alive>
|
组件特有的两个生命周期
1 2 3 4 5 6 7 8
| activated() { console.log("News被激活了"); }, deactivated() { console.log("News失活了"); }
|
前置和后置路由守卫
作用:对路由进行权限控制
分类:全局守卫、独享守卫、组件内守卫
在 ./src/router/index.js 中配置路由信息中配置:
1 2 3 4 5 6 7
| { name:'guanyu', path:'/about', component:About, meta:{isAuth:true,title:'关于'} },
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| router.beforeEach((to,from,next)=>{ console.log('前置路由守卫',to,from) if(to.meta.isAuth){ if(localStorage.getItem('school')==='atguigu'){ next() }else{ alert('学校名不对,无权限查看!') } }else{ next() } })
router.afterEach((to,from)=>{ console.log('后置路由守卫',to,from) document.title = to.meta.title || '硅谷系统' })
|
独享路由守卫
- beforeEnter:() => {}
- 写在路由配置信息中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { name:'xinwen', path:'news', component:News, meta:{isAuth:true,title:'新闻'}, beforeEnter: (to, from, next) => { console.log('独享路由守卫',to,from) if(to.meta.isAuth){ if(localStorage.getItem('school')==='atguigu'){ next() }else{ alert('学校名不对,无权限查看!') } }else{ next() } } },
|
组件内守卫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| beforeRouteEnter (to, from, next) { console.log('About--beforeRouteEnter',to,from) if(to.meta.isAuth){ if(localStorage.getItem('school')==='atguigu'){ next() }else{ alert('学校名不对,无权限查看!') } }else{ next() } },
beforeRouteLeave (to, from, next) { console.log('About--beforeRouteLeave',to,from) next() }
|
history模式和hash模式
- 对于一个 url 来说,什么是 hash 值?
- hash 值不会包含在 HTTP 请求中,即: hash 值不会带给服务器。
- hash 模式:
- 地址中永远带着
# 号,不美观。
- 若以后将地址通过第三方手机 app 分享,若 app 校验严格,则地址会被标记为不合法。
- 兼容性较好。
- history 模式:
- 地址干净,美观。
- 兼容性和 hash 模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端 404 的问题。
- 在路由配置信息中的 mode 属性决定,可选值: history | hash, 默认是 hash 模式
- 用 hash 模式,node 服务器部署静态资源时,刷新页面不会 404
- 用 history 模式,node 服务器部署静态资源时,刷新页面会 404
- 可以使用 node 中间件 connect-history-api-fallback 解决 history 模式刷新 404 的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| export default new VueRouter({ mode:"hash", routes: [ { path: "/about", component: About, }, { path: "/home", component: Home, }, ], });
|
- connect-history-api-fallback 中间件的使用:
1
| npm i connect-history-api-fallback
|
1 2 3
| const history = require( ' connect-history-api-fallback');
app.use(history())
|