VUE-组件间通信
组件的自定义事件
- 概述:是一种组件间通信的方式,适用于:子组件===>父组件
- 使用场景:A是父组件,B是子组件,B给A传递数据,那么需要在A组件中绑定自定义事件(事件的回调也在A中)
- 使用步骤
- 绑定自定义事件:
- 第一种方式:在父组件中子组件<DemoComponent @testDemo="test/> 或者 <DemoComponent v-on:testDemo="test/>
- 第二种方式:在父组件中子组件<DemoComponent ref="test/>,然后在mounted(){this.$refs.demo.$on("testDemo",this.回调函数)}
- 注意:若想让自定义事件只触发一次,可以试用once修饰符或$once方法
- 触发自定义事件:在子组件中调用this.$emit('testDemo',数据)
- 解绑自定义事件:在父组件调用this.$off('testDemo')
- 绑定自定义事件:
- 注意
- 在组件上也可以绑定原生DOM事件,需要使用native修饰符
- 通过this.$refs.xxx.$on("testDemo",回调函数)绑定自定义事件时,回调函数要么配置在methods中,要么用箭头函数,否则this指向会出现问题!
全局事件总线(较为常用)
- 概述:也是一种组件间通信的方式,适用于任意组件间的通信
- 使用步骤
- 安装全局事件总线
- 一般是在创建Vue中的beforeCreate(){Vue.prototype.$bus = this //即在vm上增加bus总线}
- 使用全局事件总线
- 接收数据:比如A组件想要接收数据,则在A组件中给$bus绑定自定义事件,且事件的回调也在A组件,如:mounted(){this.$bus.$on('xxx事件名',this.回调函数)}
- 提供数据:this.$bus.$emit('xxx事件名',数据)
- 注意:在beforeDestroy钩子中,使用$off去解绑当前组件所用到的事件
- 安装全局事件总线
消息订阅与发布
- 概述:也是一种组件间通信的方式,适用于任意组件间的通信
- 使用步骤
- 安装pubsub库:npm i pubsub-js
- 引入pubsub库:import pubsub from 'pubsub-js'
- 接收数据:比如A组件想要接收数据,则在A组件中订阅消息,订阅的回调也在A组件中
- 如:mounted(){ this.pid = pubsub.subscribe('xxx事件名',this.回调函数)} //订阅消息
- 提供数据:在对应提供数据的组件中发布消息
- 如:pubsub.publish('xxx事件名',数据)
- 注意:在beforeDestroy钩子中,调用pubsub.unsubscribe(pid)取消订阅
VUE-vuex
- vuex专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式管理(即读/写),是一种组件间通信方式且适用于任意组件间通信
- 使用场景:多个组件需要共享数据时使用
- 多个组件依赖于同一状态(数据)
- 来自不同组件的行为需要变更同一状态/数据
使用步骤
- 通常首先在store文件夹下创建js文件
- js文件初始化数据: 包括配置action、mutations、state、getters等方法
- 在main.js创建new Vue时配置store配置项
- 组件中读取共享数据:$store.state.xxx
- 组件中修改vuex数据:$store.dispatch('action中的方法名',data)或者$store.commit('mutations中的方法名',data)
- 注意:
- getters配置项:当state中的数据需要经过加工后再使用时,可以使用getters加工,组件读取getters: $store.getters.data
- 当不涉及网络请求或其他业务逻辑,组件可以越过actions,既不用通过dispatch->commit,而是直接编写commit
四个map方法
mappState方法:用于方便我们映射state中的数据为计算属性
computed:{
...mapState(test:'test',demo:'demo')//对象写法
...mapState(['test','demo'])//数组写法
}
mapGetters方法:用于方便我们映射getters中的数据为计算属性
computed:{
...mapGetters(test:'test',demo:'demo')//对象写法
...mapGetters(['test','demo'])//数组写法
}
mapActions方法:用于方便我们生成actions对话的方法,即$store.dispatch(xxx)函数
methods:{
...mapActions(test:'test',demo:'demo')//对象写法
...mapActions(['test','demo'])//数组写法
}
mapMutations方法:用于方便我们生成mapMutations对话的方法,即$store.commit(xxx)函数
methods:{
...mapMutations(test:'test',demo:'demo')//对象写法
...mapMutations(['test','demo'])//数组写法
}
模块化+命名空间
- 让代码更加容易维护,多种数据分类更加明确
-
js文件模块化+命名空间示例 const test1 = { namespaced:true,//开启命名空间 state:{test:2}, actions:{...}, mutations:{...}, getters:{test(state){...}} } const test2 = { namespaced:true,//开启命名空间 state:{x:1}, actions:{...}, mutations:{...}, getters:{test(state){...}} } const store = new Vuex.Store({ modules:{ test1,test2 } }) ...mapState('test1',['test']),//读取state数据 ...mapGetters('test1',['test']),//读取Getters数据 ...mapMutations('test1',{...}),//读取Mutations数据 ...mapActions('test1',{...})//读取Actions数据
扩展
- nextTick(也是一种常用的声明周期钩子):在下一次DOM更新结束后执行其指定的回调(即当改变数据后,基于更新后的新Dom进行某些操作时,要在nextTick所指定的回调函数中执行)
- 如:this.$nextTick(回调函数)
VUE-脚手架配置代理
在vue.config.js中配置代理
- 单一服务器代理
devServer: {
proxy: 'http://localhost:5000',
webSocketServer: false
}
- 多种服务器代理
devServer: {
proxy: {
'/api1':{ //匹配所有以'/api1'开头的请求路径
target: 'http://localhost:5000', //代理目标服务器的基础路径
changeOrigin:true, //默认为true,true:服务器收到的请求头中host为 localhost:5000;false:服务器收到的请求头中host为 localhost:8080
pathRewrite:{'^/api1':''} //替换匹配为空,避免后端服务无法识别请求真实路径
},
'/api2':{
target: 'http://localhost:5001',
changeOrigin:true,
pathRewrite:{'^/api2':''}
}
}
}
- 两者区别
- 单一服务代理
- 配置简单,但不能配置多个代理导致不能灵活控制请求是否走代理;当请求的前端资源不存在时,那么该请求才会转发给服务器(即优先匹配前端资源)
- 多服务器代理
- 可配置多个代理,灵活控制请求是否走代理;但配置略微繁琐且资源必须加前缀
- 单一服务代理
- 注意
- 代理服务器:常用的解决跨域问题方案(即浏览器请求服务器出现不同源的问题(即协议+主机名+端口中不完全一致));原理在于服务器之间传输数据不存在跨域问题
- 备注:还可以通过CORS(效果是一劳永逸-后端处理)和Jsonp处理跨域问题
- 代理服务器:常用的解决跨域问题方案(即浏览器请求服务器出现不同源的问题(即协议+主机名+端口中不完全一致));原理在于服务器之间传输数据不存在跨域问题
VUE-基于transition的过渡与动画
- 在插入、更新或者移除DOM元素时,在合适的时候给元素添加样式类名
- 官网:https://cn.vuejs.org/guide/built-ins/transition.html
- 使用步骤
- 准备好样式
- 元素进入的样式
- v-enter:进入的起点
- v-enter-active:进入过程中
- v-enter-to:进入的终点
- 元素离开的样式
- v-leave:离开的起点
- v-leave-active:进入过程中
- v-leave-to:进入的终点
- 使用<transition>包裹要过渡的元素
- 注意:若有多个元素需要过渡,则需要使用<transition-group>,且每个元素都要指定key值
- 元素进入的样式
- 准备好样式
VUE-插槽Slot
- 作用: 让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件===>子组件
- 官网:https://cn.vuejs.org/guide/components/slots.html
-
Slot分类
-
默认Slot
-
父组件
<Category>
<div>html结构1</div>
</Category>
子组件
<template>
<div>
<slot>插槽默认内容</slot>
</div>
</template>
- 具名Slot
-
父组件 <Category> <template slot="demo1"> <div>html结构1</div> </template> <template v-slot:demo2> <div>html结构2</div> </template> </Category> 子组件 <template> <div> <slot name='demo1'>插槽默认内容1</slot> <slot name='demo2'>插槽默认内容2</slot> </div> </template>
- 作用域Slot
- 数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定
VUE-vue-router
- vue-router是一个vue的插件库,专门用来实现SPA应用
- SPA应用
- 单页web应用
- 整个应用只有一个完整的页面
- 点击页面中的导航链接不会刷新页面,只会做页面的局部更新
- 数据需要通过ajax请求获取
- 路由
- 一个路由就是一组映射key:value关系,其中key为路径,value可能是function或者组件
- 路由可以分为前端路由和后端路由
- 前端路由
- value是组件component,用于展示页面内容
- 当浏览器的路径改变时,对应的组件就会显示
- 后端路由
- value是function,用于处理客户端提交的请求
- 当服务器收到请求后,根据请求路径找到匹配的函数来处理请求,返回响应数据
- 前端路由
基本使用
- 安装vue-router命令:npm i vue-router
- 使用插件:Vue.use(VueRouter)
- 编写router配置项
- //创建router实例对象,统一管理每组的路由规则
-
const router = ({ routers:[ { path: '/test1', component:Test1, //多级路由:使用children配置子级路由 children:[ { name:'hello',//给路由命名,简化路由的跳转写法 path:'test1Child1', //此处不要写成'/test1Child1',默认会加'/' component:Test1-1, //接收参数 query:{ id:id, name:name } }, { path: 'test1Child2', component:Test1-2 } ] }, { path: '/test2', component:Test2 }, ] }) export default router
-
实现切换
- <router-link to='/test1'>Test1</router-link>
- 多级路由跳转:<router-link to='/test1/test1Child1'>Test1</router-link>
- 多级路由传递参数跳转:<router-link to='{path:'/test1/test1Child1(路由命名后可简化写为hello)',query:{id:001,name:'墨行'}}'>Test1</router-link>(接收参数:$route.query.id/name)
- 指定展示位置:<router-view></router-view>
- 注意
- 路由组件通常存放在pages文件夹下,一般组件位于components文件夹下
- 切换过程中,'隐藏'的路由组件默认是被销毁的,需要时重新挂载
- 每个组件都有自己的$route属性,里面存储自己路由信息
- 整个应用只有一个router,可以通过$router属性获取
路由props参数
- 可以让路由组件更加方便收到参数
-
... props(route){ return { id:route.query.id, name:route.query.name } } ...
<router-link>的replace&push属性
- 分别是控制路由跳转时操作浏览器历史记录的模式,push是追加历史的记录,replace是替换当前记录,路由跳转时候默认push模式
- 开启replace模式:<router link replace ...>Hello<router-link>
编程式路由导航
- 不借助<router-link>实现路由跳转的另外一种方式,让路由跳转更加灵活
- 编程式路由导航相关API
this.$router.push({//push模式
name:'test1',
params:{
id:xxx,
name:xxx
}
})
this.$router.replace({//replace模式
name:'test1',
params:{
id:xxx,
name:xxx
}
})
this.$router.forward()//前进
this.$router.back()//后退
this.$router.go()//前进
缓存路由组件
- 让不展示的路由组件保持挂载,不被销毁
-
<keep alive include='test1'> <router-view></router-view> </keep-alive>
生命周期钩子activated|deactivated
- 路由组件独有的两个钩子,用于捕获路由组件的激活状态
- activated:路由组件被激活时触发
- deactivated:路由组件失活时触发
路由守卫
- 作用就是对路由进行权限控制
- 分为全局守卫,独享守卫,组件内守卫
-
router.beforeEach((to,from,next)=>{...})//全局前置守卫,初始化时执行,每次路由切换前执行 router.afterEach((to,from,next)=>{...})//全局后置守卫,初始化时执行,每次路由切换后执行 beforeEnter(to,from,next){...})//独享守卫 beforeRouteEnter(to,from,next){...})//进入组件守卫,通过路由规则,进入该组件时被调用 beforeRouteLeave(to,from,next){...})//离开组件守卫,通过路由规则,离开该组件时被调用
路由器的两种模式
- hash模式
- url中的hash值:#及其后面的内容
- hash值不会包含在HTTP请求中,即hash值不会附带发送到服务器
- url地址中永远带着#,不美观
- 若将url地址通过第三方app分享,若app校验严格则会被标记为不合法
- 兼容性较好
- history模式
- 地址干净美观
- 兼容性和hash模式相比略差
- 应用部署上线时需后端人员解决刷新页面服务器404问题(服务器端可通过第三方库解决)
VUE-UI组件库
- 移动端常用UI组件库
- PC端常用UI组件库
- Element UI:应该是大家使用最为频繁的一款
- IView UI:也称为View Design,一套基于 Vue.js 的开源 UI 组件库,主要服务于 PC 界面的中后台产品,目前也是我司使用的UI组件库[官网:介绍 - iView (iviewui.com)]