vue中组件之间的通信方式

13 篇文章 0 订阅
13 篇文章 0 订阅

vue中组件之间的通信方式

方式

1、父子组件
props / $emit / $parent / ref / $attrs

props:子组件接收父组件中绑定给子组件的值,不包括class、style等保留属性
$emit: 子组件上触发 $emit事件,可将参数作为playload一起传递给父组件
$parent: 子组件获取父实例
ref: 定义在普通元素上获取的是DOM,定义在子组件上获取的是子组件实例

2、兄弟组件
$parent / $root / eventbus / vuex
$root: 访问根组件的属性和方法

3、跨层级组件
eventbus / vuex / provide + inject

$on在vue3中被移除,所以不建议使用eventbus
$children也被移除了: 访问当前组件的所有直接子组件
$listeners也被移除了: 父作用域中所有v-on的事件监听器,但不包含带.native修饰符的

具体实现

// main.js
new Vue({
  data() {
    return {
      rootName: '我是根组件的rootName'
    }
  },
  router,
  store,
  render: h => h(App)
}).$mount('#app')

爷爷组件

<!-- GrandFather.vue -->
<template>
    <div class="grandfa-com">
        <!-- tograndFather是孙组件通过$emit触发,在父组件上绑定v-on="$listeners"传递过来的 -->
        <FatherCom @tograndFather="grandFatherFn" :toChild="attrToChild"></FatherCom> 
    </div>
</template>

<script>
import FatherCom from '@/components/FatherCom.vue'
export default {
    name: 'GrandFather',

    components: {
        FatherCom,
    },

    data() {
        return {
            grandFather: "我是爷爷",
            attrToChild: "通过$attrs向孙组件传值"
        }
    },

    provide() {  // 爷爷组件使用依赖注入的方式向孙组件传值
        return { 
            grandFather:  this.grandFather
        }
    },

    methods: {
        grandFatherFn(val) {
            console.log("爷爷接收来自孙子的数据:", val)
        }
    }
}
</script>

父组件

<!-- FatherCom.vue -->
<template>
    <div class="fa-com">
        <button @click="getChildren">$children实例</button>
        <button @click="getChildRef">$ref</button>
        <ChildCom v-bind="$attrs" v-on="$listeners" ref='child' :title="title" :title2="title" :attrTitle="attrTitle" @chToFa="ch2fa" @chToFa2="ch2fa"></ChildCom>
    </div>
</template>

<script>
import ChildCom from './ChildCom.vue'
export default {
    name: 'FatherCom',

    inheritAttrs: false,  // 父组件不继承来自爷爷组件透传的值,并在ChildCom绑定v-bind="$attrs"

    components: {
        ChildCom,
    },

    data() {
        return {
            title: "父级传递给子级title",
            attrTitle: "通过$attrs获取的属性"
        }
    },

    methods: {
        ch2fa(val) {
            console.log("c2f:", val)
        },

        getChildren() {
            console.log("children:", this.$children)
        },

        getChildRef() {
            console.log('$ref:', this.$refs.child)
        }
    }
}
</script>

子组件

<!-- ChildCom.vue -->
<template>
    <div class="child-com">
        <button @click="toFather">$emit向父级通信</button>
        <button @click="toGrandFather">$emit向爷爷级通信</button>
        <button @click="getProps">$prop获取父级传递来的数据</button>
        <button @click="getListeners">$listeners获取父级绑定的v-on事件</button>
        <button @click="getParent">$parent获取父级数据</button>
        <button @click="getAttr">$attrs获取透传</button>
        <button @click="getRoot">$root获取根元素</button>
        <button @click="getInject">获取inject内容</button>
    </div>
</template>

<script>
export default {
    name: 'ChildCom',
    props: ['title', 'title2', 'toChild'],  // toChild是爷爷组件绑定的,父组件不继承,直接绑定给子组件的
    inject: ['grandFather'],

    data() {
        return {
            cStr: "childComStr",
            f2c: this.title
        }
    },

    created() {
        console.log("props-title:", this.title)
    },

    methods: {
        toFather() {
            this.$emit('chToFa', '子组件传给父组件的消息')
        },

        toGrandFather() {
            this.$emit('tograndFather', '子组件通过v-on="$listeners"向爷爷组件通信')
        },

        getProps() {
            console.log('props:', this.$props)
        },

        getListeners() {
            console.log('listen:', this.$listeners)
        },

        getAttr() {
            console.log('attrs:', this.$attrs)
        },

        getParent() {
            console.log('parent:', this.$parent)
        },

        getRoot() {
            console.log('root:', this.$root.rootName)
        },

        getInject() {
            console.log("inject:", this.grandFather)
        }
    }
}
</script>

EventBus事件总线的实现

首先先初始化一个EventBus,全局事件总线,2种方式
方式一:创建一个eventbus.js,然后需要用到的页面import,也可以在main.js中全局引入

// eventbus.js
import Vue from 'vue'

export const EventBus = new Vue();
// main.js
import { EventBus } from './js/eventbus'

Vue.prototype.$EventBus = EventBus

方式二:直接在main.js里定义

// main.js
Vue.prototype.$EventBus = new Vue()

采用mian.js中直接定义的方式完成下面的实现:
A.vue:

<!-- A.vue -->
<template>
    <button @click="sendMsg">发送MsgA</button>
</template>
 
<script> 

export default {
    name: 'AP',
    data(){
    return{
        MsgA: 'A组件中的Msg'
    }
    },
    methods: {
        sendMsg() {
            this.$router.push('/b')
        }
    },
    destroyed() {
        this.$EventBus.$emit("aMsg", this.MsgA);
    }
}; 
</script>

B.vue:

<!-- B.vue -->
<template>
  <p>{{msgB}}</p>
  
</template>
 
<script> 
export default {
    name: 'BP',
  data(){
    return {
      //初始化一个msgB
      msgB: ''
    }
  },
  created() {
     this.$EventBus.$on("aMsg", (data) => {
     this.msgB = data;
	 this.$EventBus.$off('aMsg');  // 移除事件总线,避免频繁触发和内存泄漏
    });
  }
};
</script>

这样的话从A页面跳转到B页面时就会把数据通过eventbus传递过来;
要想B页面DOM内容同步更新要注意两个事项:
1、A页面应该把EventBus放在destoryed中触发,放事件中触发的话数据在B页面中可以拿到,但是页面不会更新
2、B页面要在ceated中接收EventBus,否则B页面可以拿到数据但也不会更新

这是因为EventBus的$on必须在 $emit 之前生成,否则会出现无法监听数据的bug,当A页面跳转去B页面的时候会先执行B的created,再执行A的destoryed,最后执行B的mounted,显然,只有在A的destoryed中emit在B的created中on才会监听到数据更新页面

当然,vue3已经移除$on方法,所以不建议使用EventBus了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值