组件间通信传值的各种方式与场景
一般情况下,组件间的通信传值分为三种情况:
- 父组件向子组件(跨级)通信传值;
- 子组件向父组件(跨级)通信传值;
- 兄弟组件间通信传值;
父组件向子组件(跨级)通信传值
-
使用prop传值,子组件使用
props接受数据parent.vue //部分代码省略--- <child :prop='data'> </child> child.vue props:['data'],使用场景:
对子组件进行传值,不会对子组件进行操作;
注意:- 当绑定静态数据时,最好也使用
v-bind,不然Vue会全部当成字符串处理(字符串传递除外); - 可以使用
v-bind='propObj'的方式,propObj是一个有属性的对象; - 可以使用
v-bind='$props'的方式,将父组件的props传值给子组件; - 单向数据流,不允许在子组件中修改prop;
- 当希望prop在子组件可以当做本地data使用时,可以在data中复制
localData=this.data。但是若prop为数组或者对象时,需使用深拷贝; - 当希望在子组件对prop进行转换时,可以使用计算属性转换。但是若prop为数组或者对象时,需使用深拷贝;
computed:{ myDataTrim(){ return this.myData.trim(); } }
7.子组件中,style/class不允许接收;
- 当绑定静态数据时,最好也使用
-
插槽
可以通过插槽的方式,将父组件的内容传递到子组件,可以在子组件中设置默认值。parent.vue //部分代码省略--- <child> hello </child> child.vue <div> <slot> 默认值 </slot> </div> //渲染结果:<div>hello</div>使用场景:
传递给子组件,在子组件特定的位置渲染展示出来。传递的内容甚至可以为DOM元素、组件等。
注意:- 使用具名插槽可以指定父组件内容传递的位置;
parent.vue //部分代码省略--- <child> <template v-slot:slotName> hello </template> //默认可以使用两种方式 <template v-slot:default> world </template> //or world </child> child.vue <div> <slot name='slotName'> 默认值1 </slot> <div> <slot> 默认值2 </slot> </div> </div> v-slot一般写在template中;- 缩写。
v-slot --> #,特殊情况:默认插槽#default;
- 使用具名插槽可以指定父组件内容传递的位置;
-
父组件获取子组件实例(ref)
在父组件中调用子组件时,设置ref属性,然后就可以通过this.$refs[设置的值]获取子组件的实例。parent.vue //部分代码省略--- <child ref='childRef'> </child> //methods getChildData(){ let data=this.$refs.childRef.data; }使用场景:
当父组件想获取子组件的数据、方法时,可以通过这种方式进行获取数据、调用方法;
注意:- 当
ref设置在DOM元素上时,获取的是DOM元素; $refs是一个对象,收集所有设置过ref的DOM元素或组件实例;
- 当
-
非prop特性(
attrs`对象中;
使用场景:- 当某些特性不想直接绑定在根元素上,可以通过
v-bind:$attrs绑定在特定的元素上; - 可以将这些特性通过
v-bind:$attrs传递给子组件的子组件---跨级传值; 注意: - 子组件中设置
inheritAttrs:false,可以使非prop的特性不绑定在根元素上; - style/class无法取消绑定;
- 当某些特性不想直接绑定在根元素上,可以通过
-
children[0].$children`跨级获取组件的实例;
使用场景:- 获取子组件的实例;
- 当组件层级不是很深时,可以通过这种方式跨级获取组件实例; 注意:
- 不适应组件层级较深的情况;
子组件向父组件(跨级)通信传值
- $emit(
自定义事件名[,...param])
父组件绑定自定义组件,子组件中调用; 传递参数可以为零个或者多个;使用场景:parent.vue //部分代码省略--- <child @event1='handMethod()'> </child> child.vue methods:{ setparent(){ this.$emit('handMethod'); } }
一般情况下,子组件调用父组件方法的方法; - 插槽prop
在子组件中的slot上v-bind进行绑定,这样就可以通过v-slot:slotName:props的方法接收数据了,所有的插槽prop都接收在一个对象中;使用场景:parent.vue //部分代码省略--- <child> <template v-slot:slot1='data'> data.data </template> </child> child.vue <slot name ='slot1' :data='data'></slot>
当组件内部使用了循环,但是又想让不同的数据有不同的展现方式时使用; - 组件上使用v-model
实现数据的"双向绑定";
在父组件使用v-model绑定需要进行"双向绑定"的数据,在子组件可以通过model:{}进行设置v-model绑定的prop和事件名,然后可以在需要调用的地方调用;使用场景:parent.vue //部分代码省略--- <child v-model='data'> </child> child.vue <div> <input type='text' :value='data' @input="$emit('customEvent', $event.target.value)"> </div> export default { model:{ prop:'data', event:'customEvent', }, props:[data] }
一般在需要父子组件的数据需要进行"双向绑定"的情况下,进行使用;
注意:- 这是一个语法糖,并不是真正意义上的双向绑定,在子组件中,让父组件绑定一个prop以及一个自定义事件;
//前面的例子 <child v-model='data'> </child> or <child :data='data' @customEvent='data=$event' > </child> - .sync---也是语法糖
当子组件向修改一个prop时,可以通过修改父组件的数据,从而达到修改的目的;使用场景:parent.vue //部分代码省略--- <child :title.sync='title'> </child> child.vue this.$emit('unpdate:title',newData);
子组件想修改prop的值时;
注意:- 这也是一个语法糖。让父组件绑定一个prop以及一个自定义事件---update:[prop的名字];
parent.vue //部分代码省略--- <child :title='title' @update:title='title=$event'> </child> listeners"`,这样可以跨级调用祖先的方法;
使用场景:- 可以在子组件中对父组件的方法进行调用;
- 可以达到跨级通信的功能;
parent[0].$parent`跨级获取组件的实例;
使用场景:- 获取父组件的实例;
- 当组件层级不是很深时,可以通过这种方式跨级获取组件实例; 注意:
- 不适应组件层级较深的情况;
$attrs和$listeners
可以在子组件中再通过v-bind:$attrs以及v-on="$listeners"的方式进行跨级的通信传值;
比如可以实现.sync和v-model的功能(需要最初传入的组件配合);
兄弟组件以及跨多级组件间传值
- vuex 使用的不多,而且相关的内容挺多的。等有空详细看看再总结一下。官方文档
- eventBus
建一个空的Vue实例作为中央事件总线;
进行将其定义在全局;
let bus = new Vue(); //一个组件中绑定 bus.$on('evnet1',()=>{ }); 组件销毁前 beforeDestroy(){ bus.$off('evnet1'); } //另外一个组件中调用 bus.$emit('evnet1'[,...param]); - 数据存储在浏览器;---骚操作
- 通过路由传值;
在created钩子函数中,获取
$route的值,进行相应的操作。
后记
对一些常用的组件间通信传值方法的使用与场景的理解,理解的比较粗略。后续可能会对Vuex以及provide/inject等方法进行一些学习---看情况而定。