VUE组件通信的几种方法

孟琳丰 2022-09-09 17:58:15

1.props/$emit

1.父组件向子组件传值props
官网介绍
父组件

<template>
   <div class="wrap">
       <div>我是Father组件</div>
       <Son
         str="我是字符串"
         :num=5
         :obj="{cont:'我是一个对象'}"
         :func="()=>{this.hello()}"
         :arr="arr"></Son>
    </div>
</template>
<script>
    import Son from './Son'
    export default {
        name: "Father",
        data(){
            return{
                arr:[1,2,3]
            }
        },
        methods:{
            hello(){
                console.log("hello world!")
            }
        },
        components:{  Son  }
    }
</script>

子组件

<template>
    <div>我是Son组件</div>
</template>
<script>
   export default {
       name: "Son",
       props:{//props列表
           arr:Array,//定义参数类型
           num:Number,
           str:String,
           str2:{
               type:String,
               default:"我是默认字符串"//定义参数默认值
           },
           func:{
               type:Function,
               required:false//定义参数是否必须值
           },
           obj:{
               type: Object,
               required:false
           }
        },
        created() {
            console.log(this.str);//我是字符串
            console.log(this.str2);//我是默认字符串
            console.log(this.num);//5
            console.log(this.func);//hello(){console.log("hello world!");}
            console.log(this.arr);//[1,2,3]
            console.log(this.obj);//{cont:'我是一个对象'}
            this.func();//hello world!
        }
    }
</script>

2.子组件向父组件传值(通过事件形式)

父组件

<template>
    <div class="wrap">
        <div>我是Father组件</div>
        <Son @func="speak" ></Son>
    </div>
</template>
<script>
import Son from './Son'
export default {
    name: "Father",
    methods:{
        speak(msg){
            console.log(msg);//我是子组件发送的消息!
        }
    },
    components:{
        Son
    }
}
</script>

子组件

<template>
    <div>
        <div>我是Son组件</div>
    </div>
</template>
<script>
export default {
    name: "Son",
    mounted() {
        this.$emit('func',"我是子组件发送的消息!");
    }
}
</script>

2.EventBus

这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。

通过 $emit 触发当前实例上的事件,并将参数传递给监听器,通过 $on 监听当前实例上的自定义事件。下面介绍通过 vm.$emit / vm.$on 实现兄弟组件传值.

在main.js种挂载全局EventBus

Vue.prototype.$EventBus = new Vue()

A组件 代码:

<template>
    <div class="wrap">
        <div>我是组件A</div>
        <button @click="sendMsg">发送</button>
    </div>
</template>
<script>
export default {
    name: "A",
    methods:{
        sendMsg(){
            this.$EventBus.$emit('sendMsg',"这是组件A发送的消息!")
        }
    }
}
 </script>

B组件 代码:

<template>
    <div>
        <div>我是组件B</div>
    </div>
</template>
<script>
export default {
    name: "B",
    mounted(){
        this.$EventBus.$on('sendMsg',(msg)=>{
            console.log(msg);//这是组件A发送的消息!
        })
    },
}
 </script>

3.provide / inject

适用于祖先组件向其所有子孙后代组件传值。

祖先组件通过 provide 定义变量后,无论组件层次有多深,它的子孙后代组件都能够通过 inject 获取变量值。

父组件代码:

<template>
  <child></child>
</template>
<script>
import Child from './Child.vue'
export default {
    provide: { title: "标题" },
    components:{ Child }
}
</script>

子组件 Child.vue代码:

<template>
  <div>
    {{title}} // 标题
    <grandson></grandson>
  </div>
</template>
<script>
import Grandson from './Grandson.vue'
export default {
    inject: ['title'],
    components:{ Grandson }
}
</script>

子组件的子组件 Grandson.vue 代码:

<template>
  <div>{{title}}</div> // 标题
</template>
<script>
export default {
    inject: ['title']
}
</script>

4.$attrs / $listeners

官网介绍

$attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。

$listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件

父组件代码

<template>
  <div class="">
    <!-- 自定义组件使用v-model,默认会利用名为 value 的 prop 和名为 input 的事件,绑定的将在子组件中使用 value 获得,
而且给myChild组件默认会添加 @input 事件 -->
    <!-- 在myChild组件里的el-input,可以通过给input添加 :value="value" v-bind="$attrs" v-on="$listeners ,
将input事件传递进去el-input,实现改变输入框能够触发父组件事件效果" -->
    <myChild
        v-model="value"
        :maxlength="2000"
        dataSon = 'dataSon'
        dataSonSon = 'dataSonSon'
        @mySonSonChange="mySonSonChange"
        @mySonChagne="mySonChagne"/>
  </div>
</template>
<script>
import myChild from './attrsAndListenersChild'
export default {
    name: '',
    components:{
        myChild
    },
    data() {
        return {
            value:''
        }
    },
    methods: {
        mySonSonChange(){
            console.log('我是父组件的myChange,但是由我子组件的子组件调用')
        },
        mySonChagne(){
            console.log('我是父组件的myChange,但是由我子组件调用')
        }
    },
}
</script>

<style lang="" scoped>
</style>

父组件中,往子组件传递了 value maxlength dataSon dataSonSon 属性,mySonSonChange mySonChagne input方法 ,其中value和input来源于v-model


myChild子组件代码

// 子组件
<template>
  <div class="">
    <el-input :value="value" v-bind="$attrs" v-on="$listeners"></el-input>
    <div>{{value.length}}/{{maxlength}}</div>
    <h1>我接收了父组件的dataSon:{{dataSon}},但是没接收父组件的dataSonSon,此时attrs={{$attrs}},将传递到下一层组件</h1>
    <el-button type="primary" @click="sonClick">点击触发父组件的mySonChagne</el-button>
    <hr />
    <!--
      这个组件里接收了 value maxlength dataSon,没接收 dataSonSon,所以通过 v-bind="$attrs" 将没接收的 dataSonSon继续往下层组件传递
    -->
    下边的子组件的子组件{{$listeners}}
    <myChildSon v-bind="$attrs" v-on="$listeners"/>
  </div>
</template>
<script>
import myChildSon from './attrsAndListenersChildSon'
export default {
    name: '',
    components:{
        myChildSon
    },
    props:{
        value:{
            type:String
        },
        maxlength:{
            type:Number
        },
        dataSon:{
            type:String
        }
    },
    data() {
        return {}
    },
    methods:{
        sonClick(){
            this.$emit('mySonChagne')
        }
    },
    created () {
        // 传入的所有v-on事件都可以在$listeners对象中找到
        console.log(this.$listeners)//{mySonSonChange: ƒ, mySonChagne: ƒ, input: ƒ}
    }
}
</script>

<style lang="" scoped>
</style>

在created中能够获取到 父组件的$listeners 对象,包含了所有v-on


myChildSon子子组件代码

<template>
  <div class="">
    <h1>这是来源于父组件的父组件的dataSonSon:{{dataSonSon}}</h1>
    <!--这个组件里接收了dataSonSon,点击按钮触发父组件的 mySonSonChange 事件-->
    <el-button type="primary" @click="sonSonCilck">点我触发父组件的父组件的mySonSonChange</el-button>
  </div>
</template>
<script>
export default {
    name: '',
    props:{
        dataSonSon:{
            type:String
        }
    },
    data() {
        return {}
    },
    methods:{
        sonSonCilck(){
            this.$emit('mySonSonChange')
        }
    },
    created () {
        // 传入的所有v-on事件都可以在$listeners对象中找到
        console.log(this.$listeners)//{mySonSonChange: ƒ, mySonChagne: ƒ, input: ƒ}
    }
}
</script>
<style lang="" scoped>
</style>

5.$parent / $children

1.子组件使用父组件的数据和方法

指定已创建的实例之父实例,在两者之间建立父子关系。子实例可以用 this.$parent 访问父实例,子实例被推入父实例的 $children 数组中。

父组件

data() {
    return {
        msg:'age'
    }
},
components: {
    Hear,//子组件
},
methods: {
    test() {
        alert(1)
    }

},

子组件

methods: {
    click() {
      console.log(this.$parent.msg);//数据
      this.$parent.test()//方法
    }
}

2.父组件使用子组件的数据和方法

this.$children 他得到的是一个数组[VueComponent, VueComponent],数组中的值就是每一个组件实例
注意:节制地使用 $parent 和 $children - 它们的主要目的是作为访问组件的应急方法。更推荐用 props 和 events 实现父子组件通信

子组件

data() {
    return {
        msg:'age'
    }
},
components: {
    Hear,//子组件
},
methods: {
    test() {
        alert(1)
    }

},

父组件

methods: {
    click() {
      console.log(this.$children[0].msg);//数据
      this.$children[0].test()//方法
    }
}

6.ref / refs

ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;
如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据.

子组件

export default {
    data() {
        return {
            msg:'vue.js'
        }
    },
    methods: {
        sayHello() {
            console.log("Hello")
        }
    },
}

父组件

<template>
  <component-a class="" ref="comA"></component-a>
</template>
export default {
    mounted() {
        const comA = this.$refs.comA
        console.log(comA.msg);//vue.js
        comA.sayHello()//Hello
    }
}

7.Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上

Vuex各个模块

state:用于数据的存储,是store中的唯一数据源

getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算

mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件

actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作

modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

...全文
48 回复 打赏 收藏 举报
写回复
回复
切换为时间正序
请发表友善的回复…
发表回复
相关推荐
发帖
VUE

1562

社区成员

Vue是一套用于构建用户界面的渐进式JavaScript框架。我们更加关注于spa单页面应用、uni-app、vue3、微前端、基于vue的低码平台。
前端 技术论坛(原bbs)
社区管理员
  • community_283
  • 槿畔
加入社区
帖子事件
创建了帖子
2022-09-09 17:58
社区公告

亲爱的CSDN小伙伴你们好,我是一个全新的社区,成立之初请CSDN的小伙伴们帮忙推广一下我们VUE社区,欢迎大家来这里讨论VUE相关问题哦~

另外对社区做出重大贡献者,可以联系版主授予称号~