Vue组件之间的通讯方式数据处理:父子组件,兄弟组件,同级组件,爷孙组件

贴一张图先建立几个组件
这里写图片描述

先讲一句
每个 Vue 实例都实现了事件接口,即:
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件

Vue 的事件系统与浏览器的 EventTarget API 有所不同。尽管它们的运行起来类似,
但是 $on 和 $emit 并不是addEventListener 和 dispatchEvent 的别名,
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。

那就同级兄弟之间数据的传递,刚才贴了兄弟之一,再贴一下它老弟
这里写图片描述
好了,老大想搞老二?他们之间怎么搞呢?
建个房啊,公共枢纽站多方便以后也划算
你可以随便建 我就不说了,我在src/assets/下创建一个js文件,内容如下
这里写图片描述
嗯,内容虽然少,但是我不想写啊,也防止你直接copy啊,哈哈
(eventBus中我们创建了一个新的Vue实例,以后它就承担起了组件之间通信的桥梁了,也就是中央事件总线。
(这句话不是我说的,不过的却是eventBus的确是这意思)

1、一句话就是我们在响应点击事件的sendMsg函数中,用$emit触发了一个自定义的userDefinedEvent事件,
并传递了一个字符串参数,而$emit实例方法触发当前实例(这里的当前实例就是bus)上的事件,附加参数就会传给监听器回调。

所以在 第二个组件里
在mounted中,监听了userDefinedEvent,并把传递过来的字符串参数传递给了$on监听器的回调函数
好了,三分归元气当然是把组建放到父级上去,注册这两个组件,并添加这两个组件的标签
这里写图片描述
算了,贴一下 总结

1、创建一个事件总线,例如demo中的eventBus,用它作为通信桥梁
2、在需要传值的组件中用bus.$emit触发一个自定义事件,并传递参数
3、在需要接收数据的组件中用bus.$on监听自定义事件,并在回调函数中处理传递过来的参数

好像有点长,算了,快一点,父子之间传递,父向子,子向父我这里放在了一个组件里
这里写图片描述
同时我们看到app.Vue里面的蓝2 是通过绑定的形式直接传进子组件的,不过是在子组件里的pros里面接受一下就能使用
这里写图片描述
里面的红1是子组件向父组件传值后(@reduce-parent) 是v-on 来监听子组件触发的事件,别瞎搞
至于下面methods里面写的,上面也说了,也不说了,好像完了…

对于vue来说,组件之间的消息传递是非常重要的,组件之间消息传递的各种方式有那些呢?
1. props和$emit
父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</head>
<body>
<div id="app"><parent></parent></div>
<script>
    Vue.component('child', {
        data() {
            return {
                childMessage: this.parentMessage
            }
        },
        template: `<div>
                        <input type="text" v-model="childMessage" @input="passData(childMessage)">
                    </div>`,
        props: ['parentMessage'],//得到父组件传递过来的数据
        methods: {
            passData(val) {
                this.$emit('getChildData', val)//触发父组件中的事件
            }
        }
    })
    Vue.component('parent', {
        template: `<div>
                    <p>this is parent compoent!{{reciveChildMemessage}}</p>
                    <child :parentMessage="parentMessage" v-on:getChildData="getChildData"></child>
                   </div>`,
        data() {
            return {
                parentMessage: 'hello',
                reciveChildMemessage: ''// 定义一个字段来接收子组件里面传来的值
            }
        },
        methods: {
            getChildData(val) {//执行子组件触发的事件
                this.reciveChildMemessage = val // 定义一个字段来接收子组件里面传来的值
                console.log(val)
            }
        }
    })
    var app = new Vue({
        el: '#app'
    })
</script>
</body>
</html>

上例中,有父组件parent和子组件child。
1).父组件传递了message数据给子组件,并且通过v-on绑定了一个getChildData事件来监听子组件的触发事件;
2).子组件通过props得到相关的message数据,最后通过this.$emit触发了getChildData事件。

2.$attrs和$listeners
第一种方式处理父子组件之间的数据传输有一个问题:如果父组件A下面有子组件B,组件B下面有组件C,这时如果组件A想传递数据给组件C怎么办呢?
Vue 2.4开始提供了$attrs$listeners来解决这个问题,能够让组件A之间传递消息给组件C。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</head>
<body>
<div id="app">
    <first></first>
</div>
<script>
    Vue.component('third',{
        template:`<div title="third, component">
                  <input type="text" v-model="$attrs.firstToThirdMessage" @input="setThirdData($attrs.firstToThirdMessage)">
                  </div>`,
        methods:{
            setThirdData(val){
                //触发父组件A中的事件
                this.$emit('getThirdData', val)
            },
        }
    })
    Vue.component('second',{
        data(){
            return {
                secondMessage:this.firstToSecondMessage
            }
        },
        template:`<div title="second, component">
                    <input type="text" v-model="secondMessage" @input="setSecondData(secondMessage)">
                     <third v-bind="$attrs" v-on="$listeners"></third>
                  </div>`,
        props:['firstToSecondMessage'],//得到父组件传递过来的数据
        methods:{
            setSecondData(val){
                //触发父组件中的事件
                this.$emit('getSecondData',val)
            }
        }
    })
    Vue.component('first',{
        template:`<div title="first, component">
                    <p>this is first compoent!</p>
                    <p>来自Second 组件的数据:{{firstToSecondMessage}}</p>
                    <p>来自third 组件的数据:{{firstToThirdMessage}}</p>
                    <second :firstToThirdMessage="firstToThirdMessage" :firstToSecondMessage="firstToSecondMessage" v-on:getThirdData="getThirdData" v-on:getSecondData="getSecondData"></second>
                 </div>`,
        data(){

            return {
                firstToSecondMessage:'hello second',
                firstToThirdMessage:'hello third' //传递给c组件的数据
            }
        },
        methods:{
            getSecondData(val){
                this.firstToSecondMessage = val
                console.log('这是来自Second组件的数据:'+ val)
            },
            //执行C子组件触发的事件
            getThirdData(val){
                this.firstToThirdMessage = val
                console.log("这是来自Third组件的数据:"+val)
            }
        }
    })

   var app = new Vue({
        el: '#app'
    })
</script>
</body>
</html>

3.中央事件总线
上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</head>
<body>
<div id="app">
    <old-brother></old-brother>
    <young-brother></young-brother>
</div>
<script>
    Vue.component('oldBrother',{
        data(){
            return {
                OldBrotherMessage:'hello youngBrother'
            }
        },
        template:`<div>
                <p>this is oldBrother compoent!</p>
                <input type="text" v-model="OldBrotherMessage" @input="passData(OldBrotherMessage)">
            </div>`,
        methods:{
            passData(val){
                bus.$emit('globalEvent',val) //触发全局事件globalEvent

            }
        }
    })
    Vue.component('youngBrother',{
        template:`<div style="border: 1px dotted red;">
                <p>this is youngBrother compoent!</p>
                <p>oldBrother传递过来的数据:{{reciveOldBrotherMessage}}</p>
            </div>`,
        data(){
            return {
                reciveOldBrotherMessage:''
            }
        },
        mounted(){
            bus.$on('globalEvent',(val)=>{//绑定全局事件globalEvent
                this.reciveOldBrotherMessage=val;
            })
        }
    })
    //中央事件总线
    var bus=new Vue();
    var app = new Vue({
        el: '#app'
    })
</script>
</body>
</html>

4. provide和inject
父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</head>
<body>
<div id="app">
    <parent></parent>
</div>
<script>
    Vue.component('child', {
            inject:['obj'],//得到父组件传递过来的数据

        data() {
            return {
                childMessage: this.obj
            }
        },
        template: `<div title="this is child compoent!">
                        <input type="text" v-model="childMessage" @input="passData(childMessage)">
                    </div>`,
        props: ['message'],//得到父组件传递过来的数据
        methods: {
            passData(val) {
                this.$emit('getChildData', val)//触发父组件中的事件
            }
        }
    })
    Vue.component('parent', {
        template: `<div title="this is parent compoent!">
                    <p>this is parent compoent!{{reciveChildMemessage}}</p>
                    <child :message="message" v-on:getChildData="getChildData"></child>
                   </div>`,
        provide:{
            obj:'test'
        },
        data() {
            return {
                message: 'hello',
                reciveChildMemessage: ''// 定义一个字段来接收子组件里面传来的值
            }
        },
        methods: {
            getChildData(val) {//执行子组件触发的事件
                this.reciveChildMemessage = val// 定义一个字段来接收子组件里面传来的值
            }
        }
    })
    var app = new Vue({
        el: '#app'
    })
</script>
</body>
</html>

5. v-model
父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input’,val)自动修改v-model绑定的值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</head>
<body>
<div id="app">
    <parent></parent>
</div>
<script>
    Vue.component('child', {
        props: {
            value: String, //v-model会自动传递一个字段为value的prop属性
        },
        data() {
            return {
                childMessage: this.value
            }
        },
        methods: {
            changeValue() {
                this.$emit('input', this.childMessage);//通过如此调用可以改变父组件上v-model绑定的值
            }
        },
        template: `<div title="this is child compoent!">
                        <input type="text" v-model="childMessage" @input="changeValue">
                  </div>`
    })
    Vue.component('parent', {
        template: `<div title="this is parent compoent!">
                        <p>this is parent compoent!</p>
                        <p>{{parentMessage}}</p>
                        <child v-model="parentMessage"></child>
                    </div>`,
        data() {
            return {
                parentMessage: 'hello'
            }
        }
    })
    var app = new Vue({
        el: '#app'
    })
</script>
</body>
</html>

6. $parent和$children

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</head>
<body>
<div id="app">
    <parent></parent>
</div>
<script>
    Vue.component('child',{
        props:{
            value:String, //v-model会自动传递一个字段为value的prop属性
        },
        data(){
            return {
                childMessage:this.value
            }
        },
        methods:{
            changeValue(){
                this.$parent.parentMessage = this.childMessage;//通过如此调用可以改变父组件的值
            }
        },
        template:`<div title="this is parent compoent!">
                    <input type="text" v-model="childMessage" @input="changeValue">
                </div>`
    })
    Vue.component('parent',{
        template:`<div title="this is parent compoent!">
                    <p>this is parent compoent!{{parentMessage}}</p>
                    <button @click="changeChildValue">点击将值传给子组件</button >
                    <child></child>
                 </div>`,
        methods:{
            changeChildValue(){
                this.$children[0].childMessage = this.parentMessage;
            }
        },
        data(){
            return {
                parentMessage:'父组件的值'
            }
        }
    })
   var app = new Vue({
        el: '#app'
    })
</script>
</body>
</html>

7.boradcast和dispatch
vue1.0中提供了这种方式,但vue2.0中没有,但很多开源软件都自己封装了这种方式,比如min ui、element ui和iview等。
比如如下代码,一般都作为一个mixins去使用, broadcast是向特定的父组件,触发事件,dispatch是向特定的子组件触发事件,本质上这种方式还是on和on和emit的封装,但在一些基础组件中却很实用。

8.vuex处理组件之间的数据交互
如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。
详情可参考:https://vuex.vuejs.org/zh-cn/

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值