说一下 Vue 组件的通信方式都有哪些?(父子组件,兄弟组件,多级嵌套组件等等)

  • 一、父组件向子组件传值
  • 二、子组件向父组件传值
  • 三、兄弟组件传值
  • 四、跨组件

一、父组件向子组件传值

1.1props方式:可以是数组或对象,用于接收父组件的数据

<div id="app">
<child-component :msg="message" :count="count"></child-component>
<button @click="count++">
点击+1
</button>
</div>
<script>
const childComponent = {
props: {
msg: String
count: Number
},
template: `<div><p>{{msg}}</p><p>{{count}}</p><div>`
}
new Vue({
el: '#app',
data: {
message:'父组件的值',
count:0
},
components:{
childComponent
}
})
</script>

1.2 通过$parent获取父组件实例的方法或者属性

这种方式,从严格意义上讲不是值的传递,而是一种 “取” (不推荐直接通过实例进行值的获取)

实例属性$parent可以获得父组件的实例,借助实例可以调用父实例中的方法,或者父实例上的属性

<div id="app">
<child-component :msg="message" :count="count"></child-component>
<button @click="count++">
点击+1
</button>
</div>
<script>
//子组件
const childComponent = {
data:() => ({
msg:'',
count:null
}),
methods: {
handleClick(){
//调用父级实例的方法
this.$parent.parentMethods();
}
}
mounted () {
// 获取父级实例中的属性
this.msg = this.$parent.message;
this.count = this.$parent.count;
}
template: `<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>`
}
// 父级
new Vue({
el: '#app',
data: {
message: '父组件的值',
count: 0
},
methods: {
parentMethod () {
console.log('我是父级的方法');
}
}
components: {
childComponent
}
})
</script>

1.3 使用修饰符.sync

修饰符.sync2.3.0+新增,它对props起到了一种修饰的作用,使用.sync进行修饰的props,意味着子组件有修改它的意图,这种情况下它只起到一个标注性作用,有它没它都不会影响逻辑

使用.sync修改上边的代码:

// 父组件 List.vue
<template>
<!-- 这里不写 .sync 也不会影响结果 -->
<List-item :title.sync="title" @update:title="updataTitle"></List-item>
</template>
<script>
import ListItem from "./ListItem";
export default {
data() {
return {
title: "我是title",
}
},
components: {
ListItem
},
methods: {
updataTitle(res) {
this.title = res;
}
}
}
</script> // 子组件 ListItem.vue
<template>
<div>
<button @click="handleClick">Click me</button>
<div>{{title}}</div>
</div>
</template>
<script>
export default {
props: {
title: String,
},
methods: {
handleClick() {
// 子组件向父组件传值
this.$emit('update:title', '我要父组件更新 title');
}
}
}
</script>

使用.sync向子组件传递多个props

当我们用一个对象同时设置多个prop的时候,也可以将这个.sync修饰符和v-bind配合使用:

<text-document v-bind.sync="doc"></text-document>

这样会把doc对象中的每一个属性(如:title)都作为一个独立的prop传进去,然后各自添加用于更新的v-on监听器。

二、子组件向父组件传值

2.1 通过事件传值$emit

使用:

子组件使用$emit发送一个自定义事件

父组件使用指令v-on监听子组件发送的事件

<div id="app">
<child-component @child-event="childEvent"></child-component>
</div>
<script>
//子组件
const childComponent={
data:()=>({
msg:'点击发送值到父组件',
count:null
}),
methods:{
handleClick(data){
this.$emit('child-event','我是子组件传过来的值');
}
}
template:`<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>`
}
// 父级
new Vue({
el:'#app',
data:{
message:'父组件的值',
count:0
},
methods:{
childEvent(data){
console.log("子组件传过来的值",data);
}
}
components:{
childComponent
}
})
</script>

2.2 通过$children获取子组件实例

$parent

2.3 通过ref注册子组件引用

虽然存在prop和事件,但是有时仍可能需要在 JavaScript 里直接访问一个子组件。为了实现这样的需求,可以使用ref特性为某个子组件设置一个 ID 引用,就是一个身份标识

<div id="app">
<child-component ref="childComponent"></child-component>
<button @click="getRefs">
获取子组件实例
</button>
</div>
<script>
//子组件
const childComponent={
data:()=>({
msg:'点击发送值到父组件',
count:null
}),
template:`<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>`
}
// 父级
new Vue({
el:'#app',
data:{
message:'父组件的值',
count:0
},
methods:{
getRefs(){
console.log("子组件传过来的值",this.$refs.childComponent.msg);
}
}
components:{
childComponent
}
})
</script>

三、兄弟组件传值

3.1Bus中央事件总线

非父子组件传值,可以使用一个空的Vue实例作为中央事件总线,结合实例方法$on$emit使用

注意:

注册的Bus要在组件销毁时卸载,否则会多次挂载,造成触发一次但多个响应的情况。

beforeDestroy(){
this.$Bus.$off('方法名',value);
}

Bus定义方式:

  • 1,将Bus抽离出来,组件有需要时引入

    // bus.js
    import Vue from 'vue';
    const Bus = new Vue();
    export default Bus;
  • 2,将Bus挂载到 Vue 根实例的原型上

    import Vue from 'vue';
    Vue.prototype.$bus = new Vue();
  • 3,将Bus注入到 Vue 根对象上

    import Vue form 'vue';
    const Bus = new Vue();
    new Vue({
    el:'#app',
    data:{
    Bus
    }
    })

    使用例子:

    <div id="app">
    <child-component ></child-component>
    <child-component-two ></child-component-two>
    </div>
    <script>
    Vue.prototype.$bus = new Vue();
    //子组件1
    const childComponent={
    data:()=>({
    msg:'我是子组件一',
    sendMsg:'我是子组件一发送的值'
    }),
    methods:{
    handleClick(){
    this.$Bus.$emit('sendMsg',this.sendMsg);
    }
    }
    template:`<div><p @click="handleClick">{{msg}}</p></p><div>`
    }
    //子组件2
    const childComponentTwo={
    data:()=>({
    msg:'我是子组件二',
    brotherMsg:''
    }),
    mounted(){
    this.$Bus.$on('sendMsg',data=>{
    this.brotherMsg = data;
    })
    },
    beforeDestroy(){
    this.$Bus.$off('sendMsg');
    }
    template:`<div><p @click="handleClick">{{msg}}</p><p>{{brotherMsg}}</p><div>`
    } // 父级
    new Vue({
    el:'#app',
    data:{},
    components:{
    childComponent,
    childComponentTwo
    }
    })
    </script>

四、跨组件

4.1$attrs$listeners

如果父组件 A 下面有子组件 B,组件 B 下面有组件 C,这时如果组件 A 直接想传递数据给 组件 C,那就行不通了!所以,这时可以使用$attrs$listeners

Vue 2.4 提供了$attrs$listeners来实现能够直接让 组件 A 传递消息给 组件 C

// 组件A
Vue.component('A', {
template: `
<div>
<p>this is parent component!</p>
<B :messagec="messagec" :message="message" v-on:getCData="getCData" v-on:getChildData="getChildData(message)"></B>
</div>
`,
data() {
return {
message: 'hello',
messagec: 'hello c' //传递给c组件的数据
}
},
methods: {
// 执行B子组件触发的事件
getChildData(val) {
console.log(`这是来自B组件的数据:${val}`);
}, // 执行C子组件触发的事件
getCData(val) {
console.log(`这是来自C组件的数据:${val}`);
}
}
}); // 组件B
Vue.component('B', {
template: `
<div>
<input type="text" v-model="mymessage" @input="passData(mymessage)">
<!-- C组件中能直接触发 getCData 的原因在于:B组件调用 C组件时,使用 v-on 绑定了 $listeners 属性 -->
<!-- 通过v-bind 绑定 $attrs 属性,C组件可以直接获取到 A组件中传递下来的 props(除了 B组件中 props声明的) -->
<C v-bind="$attrs" v-on="$listeners"></C>
</div>
`,
/**
* 得到父组件传递过来的数据
* 这里的定义最好是写成数据校验的形式,免得得到的数据是我们意料之外的
*
* props: {
* message: {
* type: String,
* default: ''
* }
* }
*
*/
props: ['message'],
data () {
return {
mymessage: this.message
}
},
methods: {
passData(val){
//触发父组件中的事件
this.$emit('getChildData', val)
}
}
}); // 组件C
Vue.component('C', {
template: `
<div>
<input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)">
</div>
`,
methods: {
passCData(val) {
// 触发父组件A中的事件
this.$emit('getCData',val)
}
}
}); var app = new Vue({
el:'#app',
template: `
<div>
<A />
</div>
`
});

4.2provideinject

熟悉 React 开发的同学对 Context API 肯定不会陌生吧!在 Vue 中也提供了类似的 API 用于组件之间的通信。在父组件中通过provide来提供属性,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject,那么就可以注入在provide中提供的数据,而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。这和 React 中的 Context API 有没有很相似!

// 定义 parent 组件
Vue.component('parent', {
template: `
<div>
<p>this is parent component!</p>
<child></child>
</div>
`,
provide: {
for:'test'
},
data() {
return {
message: 'hello'
}
}
}); // 定义 child 组件
Vue.component('child', {
template: `
<div>
<input type="tet" v-model="mymessage">
</div>
`,
inject: ['for'], // 得到父组件传递过来的数据
data(){
return {
mymessage: this.for
}
},
}); const app = new Vue({
el: '#app',
template: `
<div>
<parent />
</div>
`
});

上面的实例中,定义了组件parent和组件child,组件parent和 组件child是父子关系。

  • parent组件中,通过provide属性,以对象的形式向子孙组件暴露了一些属性
  • child组件中,通过inject属性注入了parent组件提供的数据,实际这些通过inject注入的属性是挂载到 Vue 实例上的,所以在组件内部可以通过this来访问

注意:

官网文档提及 provide 和 inject 主要为高阶插件 / 组件库提供用例,并不推荐直接用于应用程序代码中。

4.3 Vuex 状态管理

Vuex 是状态管理工具,实现了项目状态的集中式管理。工具的实现借鉴了 Flux、Redux 和 The Elm Architecture 的模式和概念。当然与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。

Vue 组件的通信方式都有哪些?的更多相关文章

  1. Vue组件间通信方式到底有几种

    1. 前言 Vue的一个核心思想就是组件化.所谓组件化,就是把页面拆分成多个组件 (component),每个组件依赖的 CSS.JavaScript.模板.图片等资源放在一起开发和维护.组件是资源独 ...

  2. vue 组件的通信方式(完整版)

    几种通信方式无外乎以下几种: Prop(常用) $emit (组件封装用的较多) .sync语法糖 (较少) $attrs & $listeners (组件封装用的较多) provide &a ...

  3. 通俗易懂了解Vue组件的通信方式

    1.前言 Vue框架倡导组件化开发,力求将一个大的项目拆分成若干个小的组件,就如同我们小时玩堆积木一样,一个大房子是由若干个小积木组成.组件化开发最大问题就是组件之间数据能够流通,即组件之间能够通信. ...

  4. Vue组件间通信方式

    一.Props传递数据 在父组件中使用子组件,本质通过v-bind绑定属性传入子组件,子组件通过props接收父组件传入的属性 <template> <div> 父组件:{{m ...

  5. vue前端开发那些事——vue组件开发

    vue的学习曲线不是很陡(相比其它框架,如anglarjs),官方文档比较全面,分为基础篇和高级篇.我们刚开始学习的时候,肯定像引用jquery那样,先把vue的js引进来,然后学习基础内容.如果仅仅 ...

  6. 认识Vue组件

    前言 Vue.js是一套构建用户界面的渐进式框架(官方说明).通俗点来说,Vue.js是一个轻量级的,易上手易使用的,便捷,灵活性强的前端MVVM框架.简洁的API,良好健全的中文文档,使开发者能够较 ...

  7. 整理4种Vue组件通信方式

    整理4种Vue组件通信方式 重点是梳理了前两个,父子组件通信和eventBus通信,我觉得Vue文档里的说明还是有一些简易,我自己第一遍是没看明白. 父子组件的通信 非父子组件的eventBus通信 ...

  8. Vue组件通信方式全面详解

    vue组件通信方式全面详解 众所周知,Vue主要思想就是组件化开发.因为,在实际的项目开发中,肯定会以组件的开发模式进行.形如页面和页面之间需要通信一样,Vue 组件和组件之间肯定也需要互通有无.共享 ...

  9. Vue组件库的那些事儿,你都知道吗?

    前段时间一直在研究Vue组件库,终于在组内派上了用场.来给大家贡献一篇关于Vue组件库的相关知识.经验不多,如果有不合理的地方还请多多指出哦--- 回想一下,在你们公司或者你们小组是否有一个以上的项目 ...

随机推荐

  1. k8s command & args

    命令和参数说明: command.args两项实现覆盖Dockerfile中ENTRYPOINT的功能,具体的command命令代替ENTRYPOINT的命令行,args代表集体的参数. 如果comm ...

  2. C++ 标准模板库(STL):vector

    目录 1. vector 1.1 vector的定义 1.2 vector容器内元素的访问 1.3 vector 常用函数实例解析 1.4 vector的常见用途 1. vector 变长数组,长度根 ...

  3. 通过SignalR技术整合即时通讯(IM)在.NET中应用落地

    1.引言 即时通讯(IM)是RDIFramework.NET敏捷开发框架全新提供的一个基于Web的即时通讯.内部聊天沟通的工具.界面美观大方对于框架内部进行消息的沟通非常方便.基于RDIFramewo ...

  4. 2019牛客暑期多校训练营(第三场)G.Removing Stones(ST+分治)

    题意:给你n堆石子 每堆有ai个 现在问你有多少个连续的区间保证最大值小于等于该区间和的两倍 思路:我们可以考虑每个区间的分割点 总是该区间的最大值 所以我们只要ST找到该区间的最大值 然后每次都枚举 ...

  5. 【uva 247】Calling Circles(图论--Floyd 传递闭包+并查集 连通分量)

    题意:有N个人互相打了M次电话,请找出所有电话圈(Eg.a→b,b→c,c→d,d→a 就算一个电话圈)并输出.(N≤25,L≤25,注意输出格式) 解法:由于N比较小所有n^2或n^3的复杂度都没有 ...

  6. 【noi 2.6_9275】&【bzoj 3398】Bullcow(DP){Usaco2009 Feb}

    题意:一共有N只牡牛(公牛)和牝牛(母牛),每2只牡牛间至少要有K只牝牛才不会斗殴.问无斗殴发生的方案数. 解法:f[i][j]表示一共i只牛,最后一只是j(0为牝牛,1为牡牛)的方案数.f[i][0 ...

  7. hdu3564 Another LIS

    Problem Description There is a sequence firstly empty. We begin to add number from 1 to N to the seq ...

  8. JavaScript——六

    magin和padding的区别:https://www.cnblogs.com/zxnn/p/8186225.html magin:兄弟之间的 padding:父子关系 body和网页边框左右距离上 ...

  9. CF1474-B. Different Divisors

    CF1474-B. Different Divisors 题意: 题目给出你一个\(d\),要求你找出一个数字\(y\),找到的\(y\)至少有四个整数因子并且任意两个因子之间的差至少为\(d\). ...

  10. K8S(03)核心插件-Flannel网络插件

    系列文章说明 本系列文章,可以基本算是 老男孩2019年王硕的K8S周末班课程 笔记,根据视频来看本笔记最好,否则有些地方会看不明白 需要视频可以联系我 K8S核心网络插件Flannel 目录 系列文 ...