Vue中常见的组件间通信方式(部分)

59 阅读2分钟

1、Props

适用场景:父 -> 子

props的三种写法:

比如我要传name,age,sex这三个数据

  • 字符串数组形式

    (简单声明接收)

    props:["name","age","sex"]
    
  • 对象形式

    (类型限制)

    props:{
      name:"String",//限制类型为字符串类型
      age:"Number",
      sex:"String"
    }
    
  • 对象形式

    较为完整点,限制更多

    props:{
        name:{
            type:"String",
            required:true,
        },
        age:{
            type:"Number",
            default:18
        },
        sex:{
            type:"String",
            required:true,
            default:"男"
        }
    }
    

其中required指是否要求必填,default指如果没有值则以default的值传参。

required和default同时出现的情况不多。

2、自定义事件

适用场景:子 -> 父

子组件要想给父组件传递数据,就先要在父组件中给子组件绑定自定义事件(事件的回调在父组件上)

绑定自定义事件(两种方式):

注:demo是自定义事件的事件名字

  • 在父组件中:

    <Father @demo="test" />
    

    <Father v-on:demo="test" />
    
  • 在父组件中:

    <Father ref="big" />
    ......
    muthods:{
        test(){
            ......//回调函数
        }
    }
    mounted(){
        this.$reds.big.$on("demo",this.test);
        //注意这里如果适用$refs方法的话,直接在里面写回调函数的时候,
        //要把回调写成箭头函数,否则this指向会出现问题!
        //如果回调在回调在methods里面就不用担心this指向了
    }
    

触发自定义事件

在子组件中:

this.$emit("demo",数据);

解绑自定义事件

this.$off("demo");

组件上也可以绑定原生DOM事件,但需要添加native修饰符

<Father @click.native="test" />

3、全局事件总线

适用场景:任意组件间通用

安装全局事件总线:

new Vue({
    ......
    beforeCreate(){
        Vue.prototype.$bus = this;//$bus就是当前的VM
    }
    .....
})

使用全局事件总线

  • 接收数据。A组件想要数据,B组件发送数据。则在A组件中给$bus绑定自定义事件,事件在回调函数在A组件身上。

    A组件中

methods:{
    test(data数据){
        ......//回调函数
    }
},
mounted(){
    this.$bus.$on("demo",this.test);
}
  • 发送数据

    B组件中:触发事件

    this.$bus.$emit("demo",数据)
    

解绑全局事件总线:

在beforeDestroy钩子中利用this.$off()解绑当前组件用到的自定义事件。

4、消息订阅与发布

适用场景:任意组件间通用

使用步骤:

  • 1、安装pubsub

    npm install pubsub-js
    
  • 2、引入pubsub

    import pubsub from "pubsub-js"
    
  • 3、接收数据。A组件要数据,B组件发送数据。

    A组件中:

    methods:{
        test(data数据){
            ......
        }
    },
    mounted(){
        this.pid = pubsub.subscribe("demo",this.test);//订阅消息
    }
    
  • 4、接收数据

    B组件中:

    pubsub.publish("demo",数据);//发布消息
    
  • 5、取消订阅

    在beforeDestroy钩子中:

    pubsub.unsunscribe(pid);
    

5、Vuex

适用场景:任意组件间通信

详细适用请看Vuex官方文档,这里只简单地写下用法。

使用步骤:

  • 1、初始化数据,配置actions、mutations、state
    export deafult {
        state:{
            name:"",
            age:0,
            sex:""
        },
        actions:{
            getData(context,value){//getData是actions的一个方法名
                context.commit("GETDATA",value);
                //调用context下的commit方法提交给mutatins
            }
        },
        mutations:{
            GETDATA(state,value){//这里为了区分是mutations里的方法,写成大写
                state.name = value.name;
                state.age = value.age;
                steta.sex = value.sex;
            }
        }
    }
    
  • 组件中读取Vuex中的数据

    this.$store.state("name")
    
  • 组件中修改Vuex中的数据

    this.$store.dispatch("getData");
    

    或者

    this.$store.commit("GETDATA");
    

注意:若没有网络请求或者其他业务逻辑,则可以直接绕过actions,然后直接commit到mutations修改数据

6、slot插槽

使用场景:父 -> 子

分类:默认插槽、具名插槽、作用域插槽

  • 一、默认插槽

子组件中:

<template>
    <h2>
        {{title}}分类
    </h2>
    <slot>如果父组件什么结构也没给,就显示这句话</slot>
</template>

父组件中:

<template>
    <Son title="游戏">
        <ul>
            <li v-for="item in games" :key="item.index">
              {{item}}
            </li>
        </ul>
    </Son>
</template>
...
data(){
    return {
        games:["洛克王国","天天酷跑","王者荣耀","QQ飞车"]
    }
}

可以理解成slot是子组件挖了一个坑,然后父组件拿着结构去填充。

  • 二、具名插槽

    子组件中:

    <template>
        <h2>
            {{title}}分类
        </h2>
        <slot name="center">
            如果父组件什么结构也没给,就显示这句话
        </slot>
    </template>
    

    父组件中:

    <template>
        <Son title="游戏">
            <ul slot="center">
                <li v-for="item in games" :key="item.index">
                  {{item}}
                </li>
            </ul>
        </Son>
    </template>
    ...
    data(){
        return {
            games:["洛克王国","天天酷跑","王者荣耀","QQ飞车"]
        }
    }
    
  • 三、作用域插槽

    子组件中:

    <template>
        <h2>
            {{title}}分类
        </h2>
        <slot :games="games">
            如果父组件什么结构也没给,就显示这句话
        </slot>
    </template>
    data(){
        return {
            games:["洛克王国","天天酷跑","王者荣耀","QQ飞车"]
        }
    }
    

    父组件中:

    <template>
        <Son title="游戏">
            <template scope="scopeData">
                {{scopeData}}
                这里其实就是传来的一个对象,里面有一个games数组
                <ul>
                    <li v-for="item in scopeData.games" 
                        :key="item.index">
                        {{item}}
                    </li>
                </ul>
            </template>
        </Son>
    </template>
    

    这里的作用域插槽,其实就是数据在子组件上,但是根据数据生成的结构需要父组件来决定。(games在子组件上,但使用数据所遍历出来的结构由父组件决定)