路由
- 现实生活中的路由:
Vue
中的路由:为了完成
SPA(single page web application)
单页面应用
理解
Vue-router
Vue
的一个插件库, 专门用来实现SPA
应用
SPA 应用
- 单页面
WEB
应用(single page web application
):SPA
- 整个应用只有一个完整的页面
- 点击页面中的导航链接不会刷新页面, 只会做页面的局部更新
- 数据需要通过
AJAX
请求获取
路由的理解
路由: 一个路由就是一组映射关系: key-value
key
: 路由value
是function
或component
路由的分类
后端路由:
- 理解:
value
是function
, 用于处理客户端提交的请求 - 工作流程: 服务器接收到一个请求时, 根据请求路径找到匹配的函数来处理请求, 返回响应数据
前端路由:
- 理解:
value
是component
, 用于展示页面 - 工作流程: 当浏览器的路径改变时, 对应的组件就会展示
路由的基本使用
安装路由
npm i vue-router
创建路由
- 在
src
中新建router
文件夹并新建index.js
文件用于创建路由
// 引入路由
import VueRouter from "vue-router"
// 引入组件
import About from '../components/About.vue'
import Home from '../components/Home.vue'
// 创建路由并导出
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
}
]
})
使用路由
- 在
main.js
中引入并使用
// 引入 Vue
import Vue from 'Vue'
// 引入根组件 App
import App from './App'
// 引入 VueRouter
import VueRouter from 'vue-router'
import router from './router'
// 使用
Vue.use(VueRouter)
new Vue({
router,
render: h() => h(App)
}).$mount('#app')
切换路由
在组件中实现路由切换, active-class
可实现高亮样式
<router-link active-class="active" to="/about">About</router-link>
<router-link active-class="active" to="/home">Home</router-link>
展示路由
- 在组件中指定展示路由的位置
<router-view></router-view>
使用路由注意点
注意
- 路由组件通常存放在
pages
文件夹中, 一般组件通常存放在components
文件夹中 - 通过切换隐藏了的路由组件, 默认是被销毁掉的, 需要的时候再去重新挂载
- 每个组件都有自己的
$route
属性, 存储自己的路由信息 - 整个应用只有一个
router
, 可以通过组件的$router
属性获取
嵌套(多级)路由
配置路由规则使用children
配置项
children
配置中的path
不要加/
跳转要写完整路径:
<router-link to="/home/news">News</router-link>
代码示例
export default new VueRouter({
routes: [
// 一级路由
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
// 二级路由
children: [
{
path: 'news', // 不要写 /news
component: News
},
{
path: 'message', // 不要写 /message
component: Message
}
]
}
]
})
路由传参
路由跳转携带参数, 共有两种传参方式:
query
传参params
传参
query 传参
- 跳转传递参数
<!-- 字符串写法 -->
<router-link :to="`/home/message/detail?id=${this.id}&name=${this.name}`"></router-link>
<!-- 对象写法 -->
<router-link :to="{
path: '/home/message/detail',
query: {
id: this.id,
name: this.name
}
}"></router-link>
- 接收参数
mounted() {
console.log(this.$route.query.id)
console.log(this.$route.query.title)
}
params 传参
router
配置
注意
使用params
传参时, 配置路由匹配规则path
中需要拼接/:xxx
用于声明接收params
- 代码示例
export default new VueRouter({
routes: [
{
path: '/home',
component: Home,
children: [
{
path: 'message',
component: Message,
children: [
{
name: 'hello', // 给路由命名
path: 'details/:id/:title', // 使用占位符声明接收 params 参数
component: Details
}
]
}
]
}
]
})
跳转传递参数
注意
params
传参的对象写法只能使用name
跳转, 不能使用path
跳转
- 代码示例
<!-- 字符串写法 -->
<router-link :to="`/home/message/detail/${this.id}/${this.name}`"></router-link>
<!-- 对象写法 -->
<router-link :to="{
<!-- path: '/home/message/detail', -->
name: 'hello',
params: {
id: this.id,
name: this.name
}
}"></router-link>
- 接收参数
mounted() {
console.log(this.$route.params.id)
console.log(this.$route.params.title)
}
命名路由
作用: 可以简化路由的跳转
使用:
- 在配置项中添加
name
属性:
export default new VueRouter({
routes: [
{
path: '/home',
component: Home,
children: [
{
path: 'message',
component: Message,
children: [
{
name: 'hello', // 给路由命名
path: 'details',
component: Details
}
]
}
]
}
]
})
简化跳转: router-link
标签的属性to
为对象时才可根据name
进行跳转
- 代码示例
<!-- 简化前: 需写完整的路径 -->
<router-link to="/home/message/details">跳转</router-link>
<!-- 简化后: 直接使用路由的命名跳转 -->
<router-link :to="{ name: 'hello' }">跳转</router-link>
<!-- 简化写法配合 query 传参 -->
<router-link :to="{
name: 'hello',
query: {
id: 1,
name: 'world'
}
}">跳转</router-link>
路由的 props 配置
作用: 让路由组件更方便的接收到参数
router 配置 props
共有三种写法:
第一种:
props
值为对象, 该对象中所有的key: value
键值对的组合都可以在组件中通过props
接收
- 代码示例
{
name: 'index',
path: '/home',
component: Home,
props: {
id: '001',
name: 'Hello World'
}
}
第二种:
props
值为布尔值, 当布尔值为真时, 此组件收到的所有params
参数都可以在组件中通过props
接收
注意
只有params
跳转传参时可以接收, query
传参无法接收
- 代码示例
{
name: 'index',
path: '/home',
component: Home,
props: true
}
第三种:
props
值为函数, 函数形参中会携带当前的route
数据, 该函数返回一个对象, 对象中的key: value
都可以在组件中通过props
接收
备注
可通过解构赋值简写
- 代码示例
{
name: 'index',
path: '/home',
component: Home,
props($route) {
return {
id: $route.query.id,
name: $route.query.name
}
}
// 简写1: 解构
props({query}) {
return {
id: query.id,
name: query.name
}
}
// 简写2: 连续解构
props({query: {id, name}}) {
return {
id,
name
}
}
}
组件接收 router 配置的 props
跟组件通信的props
接收方法相同
- 代码示例
export default {
props: ['id', 'name'],
mounted() {
console.log(this.id)
console.log(this.name)
}
}
router-link 的 replace 属性
作用: 控制路由跳转时操作浏览器历史记录的模式
浏览器的历史记录有两种写入方式:
push
: 追加历史记录, 默认为push
方式, 浏览器中可以后退replace
: 替换当前记录
- 开启
replace
模式
<route-link :replace="true" to="/home/message/details">跳转</route-link>
<route-link replace to="/home/message/details">跳转</route-link>
编程式路由
作用: 不借助<router-link>
实现路由跳转, 让路由跳转更加灵活
- 代码示例:
this.$router.push({
name: 'hello',
query: {
id: m.id,
title: m.title
}
})
this.$router.replace({
name: 'hello',
query: {
id: m.id,
title: m.title
}
})
前进: this.$router.back()
后退: this.$router.forward()
指定页面栈数量前进或后退: this.$router.go(-2)
表示后退两个页面
缓存路由组件 keep-alive
作用: 让不展示的路由组件保持挂载, 不被销毁
使用: 使用<keep-alive></keep-alive>
包裹要缓存路由组件的router-view
标签
include
: 指定要缓存的路由组件, 填写的是组件名称, 不配置将缓存该router-view
的所有组件, 指定缓存多个时写成数组
- 代码示例:
<!-- 指定缓存单个组件 -->
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
<!-- 指定缓存多个组件 -->
<keep-alive :include="['News', 'Hello', 'Home']">
<router-view></router-view>
</keep-alive>
两个新的生命周期函数-路由组件
作用: 路由组件所独有的两个钩子, 用于捕获路由组件的激活状态
当路由组件被keep-alive
缓存时, mounted
、beforeDestroy
等生命周期便无法监视到, 如果需要在组件不展示的时候清除定时器等一系列操作时, 可使用这两个生命周期出来相关业务逻辑
activated
: 路由组件被激活时触发deactivated
: 路由组件失活时触发
路由守卫
作用: 对路由进行权限限制, 保护路由的安全
分类:
- 全局守卫
- 独享守卫
- 组件内守卫
全局守卫
全局路由守卫共有两个方法:
beforeEach(to, from, next)
: 全局前置路由守卫, 初始化时及每次路由切换之前被调用to
: 将要跳转的路由信息from
: 上一个路由信息next
: 是否放行
afterEach(to, from)
: 全局后置路由守卫, 初始化时及每次路由切换之后被调用to
: 跳转的路由信息from
: 上一个路由信息
代码示例
// 全局前置路由守卫 => 初始化时 及 每次路由切换之前被调用
router.beforeEach((to, from, next) => {
console.log('全局前置路由守卫', to, from)
to.meta.isAuth ? localStorage.getItem('user') === '9ml' ? next() : alert('当前账户无权限') : next()
})
// 全局后置路由守卫 => 初始化时 及 每次路由切换之后被调用
router.afterEach((to, from) => {
console.log('全局后置路由守卫', to, from)
// 前置路由守卫放行后修改页面的标题
document.title = to.meta.title || 'test'
})
独享守卫
某一个路由所独享的路由守卫, 只有一个方法:
beforeEnter(to, from, next)
注意, 没有
afterEnter
方法meta
是路由元信息代码示例
{
name: 'homeName',
path: '/home',
component: Home,
meta: {
title: '主页'
},
beforeEnter: (to, from, next) => {
to.meta.isAuth ? localStorage.getItem('user') === '9ml' ? next() : alert('当前账户无权限') : next()
}
}
组件内守卫
组件内部的路由守卫, 共有两个方法:
beforeRouterEnter(to, from, next)
: 通过路由规则, 进入该组件时调用beforeRouterLeave(to, from, next)
: 通过路由规则, 离开该组件时调用
- 代码示例
export default {
name: 'Demo',
// 通过路由规则, 进入该组件时调用
beforeRouteEnter (to, from, next) {
console.log('About----beforeRouteEnter', to, from)
to.meta.isAuth ? localStorage.getItem('user') === '9ml' ? next() : alert('当前账户无权限') : next()
},
// 通过路由规则, 离开该组件时调用
beforeRouteLeave (to, from, next) {
console.log('About----beforeRouteLeave', to, from)
next()
}
}
hash 模式与 history 模式
路由器的两种工作模式
哈希值: 网页地址#
及其后面的内容就是hash
值, hash
值不会包含在HTTP
请求中, 即: hash
值不会带给服务器
hash 模式
- 地址中永远带着
#
, 不美观 - 若以后将地址通过第三方手机
App
分享, 若app
校验严格, 则地址会被标记为不合法 - 兼容性好
history 模式
- 地址干净, 美观
- 兼容性和
hash
模式相比略差 - 应用部署上线时需要后端人员支持, 解决刷新页面服务器
404
的问题 node
中借助connect-history-api-fallback解决history
模式页面刷新请求服务器问题