vue-router
- vue-router 是 vue的一个插件库,专门用来实现
SPA
应用。
SPA
- 单页面 Web 应用(single page web application,SPA)。
- 整个应用只有 一个完整的页面。
- 点击页面中的导航链接 不会刷新页面,只会做页面的 局部刷新。
- 数据需要通过 ajax 请求获取
路由
- 路由:一个路由就是一组映射关系(key-value)
- key 作为路径,value可能是 function 或 component
路由的分类(前端路由-后端路由)
- 前端路由
- 理解:key 是一个路径,value 是一个 component,用于展示页面内容。
- 工作过程:当浏览器路径变化时,对应的组件就会显示。
- 后端路由
- 理解:key 是一个路径,value 是一个 function,用于处理客户端提交的请求。
- 工作过程:服务器接受到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据。
基本使用
-
安装 vue-router,
npm i vue-router
或yarn add vue-router
-
应用插件:
Vue.use(VueRouter)
-
编写 router 配置项
// 该文件专门用于创建整个应用的路由器 import VueRouter from "vue-router"; import Vue from "vue"; // 应用插件 Vue.use(VueRouter) import About from "@/components/路由基本使用/About"; import Home from "@/components/路由基本使用/Home"; // 创建路由器并暴露 export default new VueRouter({ routes: [ { path: '/about', component: About }, { path: '/home', component: Home } ] })
-
指定展示位置
<router-view></router-view>
几个注意点
- 路由组件通常存放在
pages
文件夹,一般组件通常存放在components
文件夹。 - 通过切换,“隐藏”了的路由组件,默认是被销毁的,需要的时候再去挂载。
- 每个组件都有自己的
$router
属性,里面存储着自己的路由信息。 - 整个应用只有一个
routers
,可以通过组件的$router
属性获取到。
嵌套(多级)路由
-
配置路由规则,使用 children配置项:
// 如下例子 import Home from './pages/Home.vue'; import News from './pages/News.vue'; import Message from './pages/Message.vue'; export default new VueRouter({ routes: [ { path: '/home', component: Home, children: [ //通过 children 配置子级路由 { path: 'news', // 此处一定不要写:/news component: News }, { path: 'message', // 此处一定不要写:/message, component: } ] } ] });
路由的 query参数
-
传递参数
<!-- 跳转并携带 query参数,to的字符串写法 --> <router-link to="/home/.../...?id=66&title=Hello">跳转</router-link> <!-- 跳转并携带 query参数,对象的写法 --> <router-link :to="{ path: '/home/.../...', query: { id: 666, title: 'Hello' } }" >跳转</router-link>
-
接受参数(路由组件)
this.$route.query.id this.$toure.query.title
命名路由
-
作用:可以简化路由的跳转。
-
如何使用:
-
给路由命名:
{ path: '/demo', component: Demo, children: [ { path: '/test', component: Test, children: [ { name: 'hello', // 给路由命名 path: '/welcome', component: Hello } ] } ] }
-
简化跳转
<!-- 简化前,需要写完整路径 --> <router-link to="/demo/test/welcome">跳转</router-link> <!-- 简化后,直接通过名字跳转--> <router-link :to="{ name: 'hello' }" >跳转</router-link> <!-- 简化写法配合传递参数 --> <router-link :to="{ name: 'hello', query: { id: 66, title: '你好' } }" >跳转</router-link>
-
路由的params参数
-
配置路由,声明接受
params
参数{ path: '/home', component: Home children: [ { path: '/news', component: News }, { path: '/message', component: Message, children: [ { name: 'xiangqing', path: 'detail/:id/:title', // 使用占位符声明接受 params参数, component: Detail } ] } ] }
-
传递参数
<!-- 跳转并携带 params参数,to的字符串写法--> <router-link to="/home/message/xiangqing/66/你好"></router-link> <!-- 跳转并携带 params参数,to的对象写法 --> <router-link :to="{ name: 'xiangqing', params: { id: 66, title: '你好' } }">跳转</router-link>
- 特别注意:路由携带
params
参数时,若使用to
的对象写法,则不能使用path
配置项,必须使用name
配置!
-
接受参数
this.$route.params.id this.$route.params.title
路由的props配置
-
作用:让路由组件更方便的收到参数。
{ name: 'xiangqing', path: '/detail/:id', component: Detail, // 第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件 props: {x: 66}, // 第二种写法:props为布尔值,则把路由收到的所有 params参数通过props传递给Detail组件 props: true // 第三种写法:props为函数,该函数返回的对象中每一组key-value都会通过props传递给Detail组件 // props 第一个参数可以获取到 路由组件Detail的$route props($route) { return { id: $toure.query.id, title: $router.query.title } } }
<router-link>
的replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式。
- 浏览器的历史记录有两种写入方式:分别为
push
和replace
,push
是追加历史记录,replace
是替换当前记录。- 路由跳转默认为
push
- 路由跳转默认为
- 如何开启
replace
模式:<router-link replace></router-link>
编程式路由导航
-
作用:不借助
<router-link>
实现路由跳转,让路由跳转更加灵活。 -
具体编码:
// routers的两个API this.$routers.push({ name: 'xiangqing', // 或 query params: { id: xxx, title: xxx } }) this.$routers.replace({ name: 'xiangqing', params: { id: xxx, title: xxx } }) this.$routers.forward() // 前进 this.$routers.back() // 后退 this.$router.go() // 可前进可后退
缓存路由组件
-
作用:让不展示的路由组件保持挂载。
-
具体编码:
// 如果缓存多个 则:include="[组件1、组件2]" <keep-alive include="缓存的组件"> <router-view></router-view> </keep-alive>
两个新的生命周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获组件的激活状态。
- 具体名字:
activated
路由组件被激活时触发。deactivated
路由组件失活时触发。
路由守卫
-
作用:对路由进行权限控制
-
分类:全局前置守卫、独享守卫、组件内守卫
-
全局守卫
// 全局前置守卫:初始化时执行、每次路由切换前执行 router.beforEach((to, from, next)=> { if(to.meta.xxx) { // 判断当前是否需要进行权限控制(meta可以看作是一块空间 需要在路由规则进行配置 存储自己想放的内容,比如标记、标题) if( localStore.getItem('xxx') === 'xxx') { next() // 放行 } else { alert('暂无权限查看') } }else { next() } }) // 全局后置守卫:初始化后执行、每次路由切换后执行 router.afterEach((to, from)=>{ if(to.meta.title) { document.title = to.meta.title // 修改网页标题 }else { document.title = 'vue_test' } })
-
独享守卫:
// 加在需要的路由独享的路由规则里 beforEnter() { if(to.meta.xxx) { //判断当前路由是否需要进行权限控制 if(localStore.getItem('xxx') === xxx) { next() }else { alert('暂无查看权限') } }else { next() } }
-
组件内守卫
//进入守卫:通过路规则,进入该组件时被调用 beforeRouterEnter(to, from, next) { } // 离开守卫:通过路由规则,离开该组件时被调用 beforeRouterLeave(to, from, next) { }
路由器的两种工作模式
- 对于一个url来说,什么是hash值?—— #及后面的内容就是hash值。
- hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
- hash模式:
- 地址中永远带着#号,不美观。
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
- history模式
- 地址干净,美观。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务器404的问题。
-
注:使用history模式存在页面刷新存在404的问题,本质上会把路径带给服务器,服务器不知道是前端路由还是后端路由
-
解决方案:借助connect-history-api-fallback插件可以解决该问题
const express = require('express') const history = require('connect-history-api-fallback') const app = express(); app.use(history()) // 应用该插件 app.use(express.static( __dirname +'/static')) app.listen(5000, (err)=> { if(!err) console.log('服务器启动成功:http://127.0.0.1:5000') })
-