vue|说说组件通信的这几种方式🏆🏆

99 阅读2分钟

1、props和emit【适用父子组件】

props只能是父组件向子组件传值

// 父组件
<template>
    <div>
        <son :name=msg @sonSubmit="sonSubmit"></son>
        <span style="color: red">{{sonmsg}}</span>
    </div>
</template>
<script>
    import Son from "../components/son/Son";

    export default {
        name: "Props",
        components: {Son},
        data() {
            return {
                msg: '将msg通过props传递给子组件',
                sonmsg: ''
            }
        },
        methods: {
            sonSubmit(val) {
                this.sonmsg = val;
            }
        }
    }
</script>

子组件通过自定义事件,将数据emit到父组件

// 子组件
<template>
    <div>
        <div style="margin: 10px">{{name}}</div>
        <el-button size="mini" @click=emit>点击向父组件发送数据</el-button>
    </div>
</template>

<script>
    export default {
        name: "Son",
        props:{
            // 字符串形式
            name:String,
        },
        methods: {
            emit() {
                this.$emit('sonSubmit', '子组件通过$emit,向父组件传值')
            }
        }
    }
</script>

image (1).png

2、EventBus【适用父子组件、兄弟组件、任意组件】

定义EventBus.js

//事件总线
import Vue from 'vue'
export const EventBus = new Vue()

定义firstCom.vue发布新增方法

<template>
    <div>
        <el-button @click="add">点击增加数字</el-button>
    </div>

</template>

<script>
    import {EventBus} from "../../assets/js/eventbus";

    export default {
        name: "firstCom",
        data() {
            return {
                num: 0
            }
        },
        methods: {
            add() {
                // 将addtion提交到事件总线
                EventBus.$emit('addtion', {num: this.num+1})
            }
        }
    }
</script>

定义secondCom.vue订阅新增方法

<template>
    <div>{{count}}</div>
</template>

<script>
    import {EventBus} from "../../assets/js/eventbus";

    export default {
        name: "secondCom",
        data() {
            return {
                count: 0
            }
        },
        mounted() {
            //挂载完毕,完成事件订阅
            EventBus.$on('addtion', params => {
                this.count += params.num;
            })
        }
    }
</script>

定义界面,完成调用

<template>
    <div>
        <el-divider>组件1</el-divider>
        <first-com></first-com>
        <el-divider>组件2</el-divider>
        <second-com></second-com>
    </div>
</template>

<script>
    import FirstCom from "../components/eventCom/firstCom";
    import SecondCom from "../components/eventCom/secondCom";

    export default {
        name: "EventBus",
        components: {SecondCom, FirstCom}
    }
</script>

image (2).png

3、依赖注入【适用父子组件、祖孙组件】

父组件通过provide提供值

export default {
        name: "Provider",
        components: {ChildTwo},
        provide: {
            name: '父组件提供一个值name供其他组件使用'
        }
    }

子组件通过inject获取值

//组件二
import ChildThree from "./ChildThree";

    export default {
        name: "ChildTwo",
        components: {ChildThree},
        inject: ['name']
    }
</script>
// 组件三
    import ChildFour from "./ChildFour";

    export default {
        name: "ChildThree",
        components: {ChildFour},
        inject:['name']
    }
// 组件四
    export default {
        name: "ChildFour",
        inject:['name']
    }

image (3).png

4、ref和refs【适用父子组件】

子组件定义自己的属性和方法

        data() {
            return {
                name: '张三'
            }
        },
        methods: {
            sayHello() {
                console.log('hello world')
            }
        }

父组件引入子组件,ref指向子组件这个实例,通过$refs获取实例的属性和方法

<template>
    <child ref="child"></child>
</template>

<script>
    import Child from "../components/refsCom/child";

    export default {
        name: "Refs",
        components: {Child},
        mounted() {
            // 子组件属性
            console.log(this.$refs.child.name);
            // 子组件方法
            console.log(this.$refs.child.sayHello())
        }
    }
</script>

ref用在DOM上,引用指向的就是DOM元素,ref用在子组件上,引用指向的就是组件实例

5、parent和children【适用父子组件、祖孙组件】

this.$parent 的值是对象

        methods: {
            getData() {
                this.msg = this.$parent.msg;
            }
        }

this.$children的值是数组

methods: {
  getMsg() {
      this.data = this.$children[0].message;
  }
}

注意点

(1)通过this.$children得到的数组是无序的

(2)通过parent访问到是上一级父组件的实例,可以使用root来访问根组件的实例

(3)在根组件#app拿到的parent的到的是new Vue()实例,在这个实例基础上再去拿parent得到的是undefined,在最底层子组件利用$children拿到的是空数据

6、attrs和listeners【适用于隔代组件】

$attrs继承父组件的所有属性(除了props传递属性、class、style)一般用在子组件上

// 父组件
<template>
    <child-one :attr1="attr1" :attr2="attr2" @toFather="say"></child-one>
</template>

<script>
    import ChildOne from "../components/attrs/ChildOne";

    export default {
        name: "Attrs",
        components: {ChildOne},
        data() {
            return {
                attr1: '参数1',
                attr2: '参数2',
            }
        },
        methods: {
            say(msg) {
                console.log(msg);
            }
        }
    }
</script>

$listeners相当于继承父组件的事件

//子组件1
<template>
    <div>
        <span>ChildOne:只接收一个参数attr1:{{attr1}}</span><br/>
        <span>现有的参数是:{{this.$attrs}}</span><br/>
        <grand-child v-bind="$attrs" v-on="$listeners"></grand-child>
    </div>
</template>

<script>
    import GrandChild from "./GrandChild";

    export default {
        name: "ChildOne",
        components: {GrandChild},
        props: ['attr1'],
        inheritAttrs: false
    }
</script>
//子组件2
<template>
<div>
    <span>GrandChild:只接收一个参数attr2:{{attr2}}</span><br/>
    <span>现有的参数是:{{this.$attrs}}</span>
</div>
</template>

<script>
    export default {
        name: "GrandChild",
        props:['attr2'],
        inheritAttrs: false,
        created() {
            this.$emit('toFather','hello attrs and listeners')
       }
    }
</script>

image (4).png

7、vuex【任意组件】

如果很多组件需要处理公共的数据,就把公共的数据抽离出来放到vuex中