QX-AI初始化中...
暂无预设简介,请点击下方生成AI简介按钮。
路由route
前端路由用于实现 SPA应用(单页Web应用)
SPA应用:
(1) 整个应用只有一个完整的页面
(2) 点击导航区不刷新页面,只做页面的局部更新
(3) 数据需要通过 ajax 请求获取
每个路由都是路径与组件的映射关系,当浏览器的路径改变时,对应的组件就会显示
路由基本使用
在 Vue 中使用路由需安装 vue-router 插件
安装: npm install vue-router
,最新版本仅支持 Vue3,Vue2 需使用 vue-router@3
使用步骤:
(1) 创建路由器
(2) 注册路由
(3) 使用路由
(4) 编写路由组件
注意:
(1) 不断切换路由时,路由组件在重复地销毁和挂载,即重复地经过完整的生命周期
(2) vue-router 插件会向 vm 和 vc 身上添加 $route
(当前路由) 和 $router
(全局路由器) 两个属性
1、创建路由器:
通常在 src 目录下新建 router/index.js
使用 new VueRouter()
创建路由器实例
/router/index.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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, }, ] });
|
2、注册路由:
在 new Vue()
时传入刚刚创建好的路由器实例
因为 vue-router 是插件,还要 Vue.use()
安装插件
main.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import Vue from "vue"; import App from "./App.vue"; import VueRouter from "vue-router";
import router from "@/router"
Vue.config.productionTip = false;
Vue.use(VueRouter)
new Vue({ el: "#app", render: h => h(App), router, })
|
3、使用路由:
vue-router 提供了几个特殊标签来使用路由
<router-link>
会被解析为 A 标签,点击后切换路由
<router-view>
指定路由组件的呈现位置
App.vue1 2 3 4 5 6 7 8 9 10 11 12
| <template> <div> <router-link to="/home" active-class="active">Home</router-link> <router-link to="/about" active-class="active">About</router-link> <router-view></router-view> </div> </template>
|
4、编写路由组件:
一般组件:直接在另一个组件模板中写组件标签,一般放在 components 文件夹
路由组件:配置在路由器中,通过切换路由动态展示和销毁,一般放在 pages 文件夹
/pages/Home.vue1 2 3 4 5 6
| <template> <div> <h2>我是Home组件</h2> </div> </template>
|
/pages/About.vue1 2 3 4 5 6
| <template> <div> <h2>我是About组件</h2> </div> </template>
|
嵌套、多级路由
效果:
使用 children 属性配置子路由
/router/index.js1 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
| import VueRouter from 'vue-router'; import About from '@/pages/About.vue'; import Home from '@/pages/Home.vue'; import Message from '@/pages/HomePages/Message.vue'; import News from '@/pages/HomePages/News.vue';
export default new VueRouter({ routes: [ { path: '/about', component: About }, { path: '/home', component: Home, children: [ { path: 'news', component: News }, { path: 'message', component: Message } ], }, ] });
|
修改 Home.vue 组件加上二级路由切换
/pages/Home.vue1 2 3 4 5 6 7 8 9 10
| <template> <div> <h2>我是Home组件</h2> <router-link to="/home/message" active-class="active">Message</router-link> <router-link to="/home/news" active-class="active">News</router-link> <router-view></router-view> </div> </template>
|
新建二级路由组件 Message.vue 和 News.vue
Message.vue 和 News.vue1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <h2>Home的二级路由Message</h2> </div> </template>
<template> <div> <h2>Home的二级路由News</h2> </div> </template>
|
route的属性
获取route:组件中 this.$route
,路由守卫中的 to、from 参数
route上常用属性:
- fullPath 该路由的完整路径,带参数
- meta 一个对象,允许程序员自由地往里面加内容,可以在配置路由时就设置
- name 路由的名字
- params params参数
- path 路由路径
- query 查询字符串参数
路由query传参
通过 url 的 query(查询字符串)参数给子路由组件传参
使用:
/pages/HomePages/Message.vue1 2 3 4 5 6 7 8 9 10 11 12
| <router-link :to="`/home/message/detail?id=${item.id}&title=${item.title}`">{{ item.title }}</router-link>
<router-link :to="{ path: '/home/message/detail', query: { id: item.id, title: item.title } }"> {{ item.title }}</router-link>
|
子路由组件中通过 $route.query.<key>
获取 query 参数
/pages/HomePages/MessageDetail.vue1 2
| <h3>{{ $route.query.id }}</h3> <h3>{{ $route.query.title }}</h3>
|
命名路由
给路由起名字,可以简化一些编码工作
/router/index.js1 2 3 4 5 6 7 8 9 10 11 12 13 14
| { name: 'Message', path: 'message', component: Message, children: [ { name: 'MessageDetail', path: 'detail', component: MessageDetail } ] }
|
使用 name 替代 path 配置,也能跳转路径
/pages/HomePages/Message.vue1 2 3 4 5 6 7 8 9
| <router-link :to="{ name: 'MessageDetail', // path: '/home/message/detail', query: { id: item.id, title: item.title } }">{{ item.title }}</router-link>
|
路由params传参
使用 params 传参需要在路由 path 配置中写上 url 参数(占位符)
/router/index.js1 2 3 4 5 6
| { name: 'MessageDetail', path: 'detail/:id/:title', component: MessageDetail }
|
传参:使用 params 传参,路径只能用 name 写法,不能写 path
/pages/HomePages/Message.vue1 2 3 4 5 6 7
| <router-link :to="{ name: 'MessageDetail', params: { //传params参数 id: item.id, title: item.title } }">{{ item.title }}</router-link>
|
获取参数: $route.params
/pages/HomePages/MessageDetail.vue1 2
| <h3>{{ $route.params.id }}</h3> <h3>{{ $route.params.title }}</h3>
|
路由props配置
在路由配置中加上 props: true
,该路由组件收到的所有 params 参数都会以 props 形式呈现
/router/index.js1 2 3 4 5 6 7 8 9 10
| { name: 'MessageDetail', path: 'detail/:id/:title', component: MessageDetail, props: true }
|
接收 props
/pages/HomePages/MessageDetail.vue1 2 3 4 5
| export default { name: 'MessageDetail', props: ['id', 'title'], }
|
将 props()
写成函数式,参数是该路由 $route ,可以自定义返回值,不再局限于之前只能传 params 参数
/router/index.js1 2 3 4 5 6 7 8 9 10 11 12
| { name: 'MessageDetail', path: 'detail/:id/:title', component: MessageDetail, props({params,query}){ return { id: params.id, title: query.title } } }
|
replace属性
<router-link>
的 replace 属性
作用:控制路由跳转时,操作浏览器历史记录的模式为 replace
操作浏览器历史记录有 push(默认) 和 replace 两种模式
(1) push 追加历史记录
(2) replace 替换当前记录,使浏览器不能通过后退返回之前的路径
1 2
| <router-link to="/home" active-class="active" replace>Home</router-link> <router-link to="/about" active-class="active" replace>About</router-link>
|
编程式路由
不使用 <router-link>
标签,通过调用 $router
上的方法,来控制路由的跳转
$router
原型上的 push()
和 replace()
方法分别以push 和 replace 两种模式跳转路由,都接收一个配置对象,内容和 to 属性中的一样
/pages/HomePages/Message.vue1 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
| <button @click="pushShow(item)">push跳转</button> <button @click="replaceShow(item)">replace跳转</button>
<script>
methods: { pushShow(item){ this.$router.push({ name: 'MessageDetail', params: { id: item.id, title: item.title } }) }, replaceShow(item){ this.$router.replace({ name: 'MessageDetail', params: { id: item.id, title: item.title } }) } }
</script>
|
$router
的原型上还有其它方法
(1) back()
后退
(2) forward()
前进
(3) go()
前进或后退几个历史记录
在 vue-router 插件的某些版本,使用编程式路由时,相同路径跳转会报错,在路由配置文件中加上这段代码即可
/router/index.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
let originPush = VueRouter.prototype.push; let originReplace = VueRouter.prototype.replace;
VueRouter.prototype.push = function(location,resolve,reject) { if(resolve && reject) { originPush.call(this,location,resolve,reject); } else { originPush.call(this,location,()=>{},()=>{}); } } VueRouter.prototype.replace = function(location,resolve,reject) { if(resolve && reject) { originReplace.call(this,location,resolve,reject); } else { originReplace.call(this,location,()=>{},()=>{}); } }
|
缓存路由组件
切换路由,旧的路由组件会被销毁,在该组件中的用户输入等操作都会丢失
要想切换路由不销毁旧的组件,可以将 <router-view>
放入 <keep-alive>
标签中,include 属性指定要缓存的组件名(默认全缓存)
作用:让不展示的路由组件保持挂载,不被销毁
/pages/Home.vue1 2 3 4 5
| <router-link to="/home/message" active-class="active">Message</router-link> <router-link to="/home/news" active-class="active">News</router-link> <keep-alive include="News-"> <router-view></router-view> </keep-alive>
|
两个新钩子
<keep-alive>
给能被其缓存的路由组件添加了两个新的生命周期钩子
(1) activated()
路由组件被激活时
(2) deactivated()
路由组件失活时
作用:在 activated()
中开启定时器、发AJAX请求等,在 deactivated()
中关闭定时器等
路由守卫
作用:对路由进行权限控制
分类:全局守卫,独享守卫,组件内守卫
在前端业务中,经常有需要配合后端校验权限后才能打开的页面,如个人中心、订单记录等等,通过路由守卫就能在切换路由前,对权限进行校验,然后控制切不切换页面(放行),或跳转到某一页面(登陆页)
所有守卫本质都是函数,除了全局后置守卫没有第三个参数(next)之外,都有三个参数:
(1) to 要切换的路由对象
(2) from 切换前的路由对象
(3) next 一个函数,无参时切换to的路由,有参时切换到指定路由
三种守卫相互配合实现业务
全局守卫
全局路由守卫:监测所有路由的切换,只要切换路由,就会经过全局守卫的业务逻辑
分类:
(1) 全局前置守卫:在切换路由前触发的守卫
(2) 全局后置守卫:在成功切换路由后触发的守卫
配置全局守卫:在路由配置文件中,通过路由器上的两个方法配置全局守卫
(1) beforeEach(() => {})
全局前置守卫
(2) afterEach(() => {})
全局前置守卫
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('切换路由前'); console.log(to); console.log(from); next(); })
router.afterEach((to, from) => { console.log('切换路由后'); console.log(to); console.log(from); if (to.meta.title) { document.title = to.meta.title; } })
|
独享守卫
独享路由守卫: beforeEnter()
只监测某个路由,要切换到该路由,才触发该守卫
注意:独享路由守卫没有后置,只在切换到该路由前触发
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
| const router = new VueRouter({ routes: [ { name: 'About', path: '/about', component: About, meta: { title: '关于' }, beforeEnter(to, from, next) { console.log('切换到关于路由前'); console.log(to); console.log(from); setTimeout(() => { next(); }, 1000); }, },
] });
|
组件内守卫
组件内路由守卫:只在某一路由组件实例中生效的守卫,控制进入和离开该组件
分类:
(1) beforeRouteEnter()
通过路由规则 要进入该组件前 触发
(2) beforeRouteLeave()
通过路由规则 要离开该组件前 触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| export default { name: 'Home-', beforeRouteEnter(to, from, next){ console.log('要进入该组件'); console.log(to); console.log(from); next(); }, beforeRouteLeave(to, from, next){ console.log('要进入该组件'); console.log(to); console.log(from); next(); } }
|
路由器两种工作模式
路由器有两种工作模式:
(1) hash 模式:url中带 # 号,如 localhost:8080/#/home
(2) history 模式:url中不带 # 号 如 localhost:8080/home
1、hash 模式:
- 对于 url 来说,# 号后面的内容都是 hash 值,不会包含在 HTTP 请求的路径中,# 号后面的路径只是 vue 路由器工作所需
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
- 兼容性较好,无需后端特地去处理路径问题
2、history 模式:
- url 样子较符合常理,也美观
- 项目上线后,需要后端去分辨前端路由和后端路由,返回不同的资源,解决 vue 这种单页应用程序切换路由后,刷新页面服务端404的问题,
mode 配置,指定路由器工作模式
1 2 3 4 5
| const router = new VueRouter({ mode: 'history', })
|
NodeJS-Express 通过中间件 connect-history-api-fallback 自动处理路径问题
Element-UI
组件化编码催生出了许多优秀的UI组件库,导入即可使用
以 Element-UI 为例,vue2 使用 Element,vue3 用 Element Plus
使用组件库更多的是去看其提供的文档
安装: npm i element-ui -S
全部引入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import Vue from "vue"; import App from "./App.vue";
import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false;
Vue.use(ElementUI);
new Vue({ el: "#app", render: h => h(App), })
|
按需引入:
安装 babel-plugin-component
修改 babel.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| module.exports = { presets: [ '@vue/cli-plugin-babel/preset', ["@babel/preset-env", { "modules": false }] ], plugins: [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
|
然后就可以按需引入了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import Vue from "vue"; import App from "./App.vue";
import { Button,Row,DatePicker } from 'element-ui';
Vue.config.productionTip = false;
Vue.use(Button); Vue.use(Row); Vue.use(DatePicker);
new Vue({ el: "#app", render: h => h(App), })
|
使用组件:看文档,cv使用组件标签
1 2 3 4 5
| <el-button type="primary">主要按钮</el-button> <el-date-picker type="date" placeholder="选择日期"> </el-date-picker>
|
项目上线
打包:npm run build
生成 dist 文件夹
将打包出的文件部署到服务端,交给后端去搞