Vue组件间通信的8种方式
1.常用的父子组件通讯方式:props,$emit
父组件传入属性,子组件通过props来接收,在子组件中就可以用this.xxx方式使用。
子组件通过$emit(事件名,参数)向外弹出一个自定义事件,在父组件中的属性监听事件,可以获得子组件中传出来的值
//父组件 <com-view :show="isShow" @onClick="getComView"></com-view> //子组件 props: { isShow:{ type: Boolean, value: false, },
}, data() { return { name: '123123', }; }, methods: { onComView(){ this.$emit('onClick',name); }, }
2.$parent,$children
通过 $parent,$children 来访问组件实例,进而去获取 或者 改变父子组件的值。 (仅限于父子组件之间,不推荐使用,因为不利于维护,一旦组件层次发生了变化,就需要更改其中的层次关系)
需要注意边界,最外层的#app 的$parent得到的是Vue实例,在Vue实例上再去取$parent 就是undefined了。 在最底层的组件中 $children是[]。
以父组件为桥梁去注册事件和触发事件来实现的兄弟组件通讯
//子组件一 this.$parent.$on('confirm',handleConfirm); //子组件二 this.$parent.$emit('confirm',list);
获取第一个子组件的数据和调用根组件的方法
//获取第一个子组件的数据 console.log(this.$children[0].msg); //调用根组件的方法 this.$root.handleRoot();
3.$ref
通过引用的方式获取子节点,常用于父组件中调用子组件的方法或者获取子组件的属性。
注意:如果绑在的是v-for的节点上,那么获取到的是一个数组。
//Child.vue export default { data() { return { name: '123123', }; }, methods: { getComView(val){ //接收子组件传回的数据信息 console.log(val); }, } } //Parent.vue <template> <div> <child ref="child"></child> </div> </template> <script> export default {
mounted(){ const child = this.$refs.child; console.log(child.name); //123123 child.getComView('调用了子组件的方法'); }, } </script>
4.provide/inject
依赖注入,常见于插件或者组件库里。
多个组件嵌套时,顶层组件provide提供变量,后代组件都可以通过inject来注入变量。
//顶屋组件 export default { provide() { return { name: '123123', }; }, } //后代组件 export default { inject:['name'] }
缺陷:传递的数据不是响应式的,inject接收到数据后,provide中的数据改变,但是后代组件中的数据不会改变。所以 建议传一些常量或者方法。
//父组件 export default { //方法一 不能获取methods中的方法 provide:{ name:'123123', }, //方法二 不能获取data中的属性 provide(){ return{ name:'123123', someMethod:this.someMethod //methods中的方法 } }, methods: { someMethod(){ console.log('这是注入的方法') }, } } //后代组件 export default { inject:['name','someMethod'], mounted(){ console.log(this.name); this.someMethod(); } }
5.EventBus 事件总线 (任意两个组件通讯)
//方法一 //抽离成一个单独的js文件Bus.js,然后在需要的地方引入 //Bus.js import Vue from "vue" export default new Vue() //方法二 直接挂载到全局 //main.js import Vue from "vue" Vue.prototype.$bus = new Vue() //方法三 注入到Vue根对象上 //main.js import Vue from "vue" new Vue({ el:"#app", data:{ Bus:new Vue() } })
<template> <button @click="handlerClick">按钮</button> </template> import Bus from "./Bus.js" export default{ methods:{ handlerClick(){ //自定义事件名 sendMsg Bus.$emit('sendMsg','这是向外部发送的数据'); } } } //在需要接收外部事件的组件内 import Bus from "./Bus.js" export default{ mounted(){ //监听事件的触发 Bus.$on('sendMsg',data=>{ console.log('这是接收到的数据',data); }) } beforeDestoy(){ //取消监听 Bus.$off('sendMsg'); } }
用 $emit去监听,用$on去触发,注意需要$off来取消监听,否则可能会造成内存泄漏。
6.$attrs、$listener
适用于多级组件嵌套,但是不做中间处理的情况。比如祖先组件向孙子组件传递数据。
$attrs 可以获取父组件传进来,但是没有用props接收的属性。
可以通过v-bind="$attrs"传入内部组件。
搭配inheritAttrs使用,这个只是用来控制attrs是否在DOM中渲染。
//父组件 <child :title="title" :desc="desc"></child> //子组件 <template> <div> <h2>{{title}}</h2> <p>{{$attrs.desc}}</p> </div> </template> <script> export default { props:['title'], //… } </script>
$listeners 包含父作用域中的(不包含.native的) v-on时间监听器。
可以通过v-on="$listeners"来传入内部组件。
7.Vuex 状态管理器
集中式存储管理所有组件的状态。
可以解决 多个视图依赖同一个状态 或者是 来自不同视图的行为需要变更同一个状态 的问题。
8.localStorage/sessionStorage
持久化存储。