说一下 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. MVC架构 项目实践

    MVC MVC架构程序的工作流程 springmvc 中dao层和service层的区别 项目实践 项目目录 项目实现流程 JSP登录页面View层 LoginServletjavaControlle ...

  2. [The Preliminary Contest for ICPC Asia Shanghai 2019] B-Light bulbs(差分+思维)

    前言 最近有很多算不上事的事,搞得有点心烦,补题难免就很水,没怎么搞,自我检讨一番~~ 说实话网络赛题目的质量还是挺高的,题目都设计的挺好的,很值得学习.这场比赛那会只有我们大二的在做,其他人去参加$ ...

  3. 【洛谷 p3383】模板-线性筛素数(数论)

    题目:给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内).(N<=10000000,M<=100000) 解法:1.欧拉筛O(n),数组近乎100KB:2.( ...

  4. 【noi 2.6_9289】Ant Counting 数蚂蚁{Usaco2005 Nov}(DP)

    题意:有M个家族的蚂蚁,各Ni只(互相相同).问选出 l~r 只的不同方案数. 解法:很基础的一种DP,不要被"排列组合"所迷惑了啊~我之前接触过这个类型,可惜又忘了,一定要记住! ...

  5. P1073 最优贸易(最短路)

    题目描述 CC C国有n n n个大城市和m mm 条道路,每条道路连接这 nnn个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 mmm 条道路中有一部分为单向通行的道路,一部分为 ...

  6. Dire Wolf——HDU5115

    Dire wolves, also known as Dark wolves, are extraordinarily large and powerful wolves. Many, if not ...

  7. hdu3635 Dragon Balls

    Problem Description Five hundred years later, the number of dragon balls will increase unexpectedly, ...

  8. Codeforces Round #582 (Div. 3) E. Two Small Strings (构造,思维,全排列)

    题意:给你两个长度为\(2\)的字符串\(s\)和\(t\),你需要构造一个长度为\(3n\)的字符串,满足:含有\(n\)个\(a\),\(n\)个\(b\),\(n\)个\(c\),并且\(s\) ...

  9. Codeforces Round #681 (Div. 2, based on VK Cup 2019-2020 - Final) B. Saving the City (贪心,模拟)

    题意:给你一个\(01\)串,需要将所有的\(1\)给炸掉,每次炸都可以将一整个\(1\)的联通块炸掉,每炸一次消耗\(a\),可以将\(0\)转化为\(1\),消耗\(b\),问将所有\(1\)都炸 ...

  10. 【ybt金牌导航1-2-4】免费馅饼

    免费馅饼 题目链接:ybt金牌导航1-2-4 题目大意 有一个直线,在某一个时刻有一个馅饼会出现在一些位置,有它的价值. 一个人一开始可以站在直线的任意地方,然后他每个时刻可以不移动,或向任意一边移动 ...