间歇性笔记--Vue组件间通信传值的各种方式

1,398 阅读2分钟

组件间通信传值的各种方式与场景

一般情况下,组件间的通信传值分为三种情况:

  1. 父组件向子组件(跨级)通信传值;
  2. 子组件向父组件(跨级)通信传值;
  3. 兄弟组件间通信传值;

父组件向子组件(跨级)通信传值

  • 使用prop传值,子组件使用props接受数据

        parent.vue
        //部分代码省略---
        <child 
            :prop='data'>
        </child>
    
        child.vue
        props:['data'],
    

    使用场景:
    对子组件进行传值,不会对子组件进行操作;
    注意:

    1. 当绑定静态数据时,最好也使用v-bind,不然Vue会全部当成字符串处理(字符串传递除外);
    2. 可以使用v-bind='propObj'的方式,propObj是一个有属性的对象;
    3. 可以使用v-bind='$props'的方式,将父组件的props传值给子组件;
    4. 单向数据流,不允许在子组件中修改prop;
    5. 当希望prop在子组件可以当做本地data使用时,可以在data中复制localData=this.data。但是若prop为数组或者对象时,需使用深拷贝;
    6. 当希望在子组件对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元素、组件等。
    注意:

    1. 使用具名插槽可以指定父组件内容传递的位置;
          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>
      
    2. v-slot一般写在template中;
    3. 缩写。v-slot --> #,特殊情况:默认插槽#default;
  • 父组件获取子组件实例(ref)
    在父组件中调用子组件时,设置ref属性,然后就可以通过this.$refs[设置的值]获取子组件的实例。

        parent.vue
        //部分代码省略---
        <child ref='childRef'>
        </child>
        //methods
        getChildData(){
            let data=this.$refs.childRef.data;
        }
    

    使用场景:
    当父组件想获取子组件的数据、方法时,可以通过这种方式进行获取数据、调用方法;
    注意:

    1. ref设置在DOM元素上时,获取的是DOM元素;
    2. $refs是一个对象,收集所有设置过ref的DOM元素或组件实例;
  • 非prop特性(attrs)  
  当父组件设置的特性在子组件中没有被接收时,会收集在`attrs`对象中;
    使用场景:

    1. 当某些特性不想直接绑定在根元素上,可以通过v-bind:$attrs绑定在特定的元素上;
    2. 可以将这些特性通过v-bind:$attrs传递给子组件的子组件---跨级传值; 注意:
    3. 子组件中设置inheritAttrs:false,可以使非prop的特性不绑定在根元素上;
    4. style/class无法取消绑定;
  • children  
  可以获取子组件的实例,进而可以获取/设置子组件数据,也可以调用子组件的方法;  
  可以通过`children[0].$children`跨级获取组件的实例;
    使用场景:

    1. 获取子组件的实例;
    2. 当组件层级不是很深时,可以通过这种方式跨级获取组件实例; 注意:
    3. 不适应组件层级较深的情况;

子组件向父组件(跨级)通信传值

  • $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]
        }
    
    使用场景:
    一般在需要父子组件的数据需要进行"双向绑定"的情况下,进行使用;
    注意:
    1. 这是一个语法糖,并不是真正意义上的双向绑定,在子组件中,让父组件绑定一个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的值时;
    注意:
    1. 这也是一个语法糖。让父组件绑定一个prop以及一个自定义事件---update:[prop的名字];
    parent.vue
        //部分代码省略---
        <child 
            :title='title'
            @update:title='title=$event'>
        </child>
    
  • listeners  
  一个对象。包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器;  
  可以通过`v-on="listeners"`,这样可以跨级调用祖先的方法;
    使用场景:
    1. 可以在子组件中对父组件的方法进行调用;
    2. 可以达到跨级通信的功能;
  • parent  
  可以获取父组件的实例,进而可以获取/设置父组件数据,也可以调用父组件的方法;  
  可以通过`parent[0].$parent`跨级获取组件的实例;
    使用场景:
    1. 获取父组件的实例;
    2. 当组件层级不是很深时,可以通过这种方式跨级获取组件实例; 注意:
    3. 不适应组件层级较深的情况;

$attrs$listeners

可以在子组件中再通过v-bind:$attrs以及v-on="$listeners"的方式进行跨级的通信传值;
比如可以实现.syncv-model的功能(需要最初传入的组件配合);

兄弟组件以及跨多级组件间传值

  1. vuex 使用的不多,而且相关的内容挺多的。等有空详细看看再总结一下。官方文档
  2. eventBus 建一个空的Vue实例作为中央事件总线; 进行将其定义在全局;
    let bus = new Vue();
    //一个组件中绑定
    bus.$on('evnet1',()=>{
    
    });
    组件销毁前
    beforeDestroy(){
        bus.$off('evnet1');
    }
    //另外一个组件中调用
    bus.$emit('evnet1'[,...param]);
    
  3. 数据存储在浏览器;---骚操作
  4. 通过路由传值; 在created钩子函数中,获取$route的值,进行相应的操作。

后记

对一些常用的组件间通信传值方法的使用与场景的理解,理解的比较粗略。后续可能会对Vuex以及provide/inject等方法进行一些学习---看情况而定。