关于Vue的各种通信方式

本文深入探讨Vue.js中各种组件通信方式,包括prop、emit、vuex的基础通信,provide和inject的跨层级通信,dispatch和broadcast的上下级通信,attrs和listeners的属性监听,$parent和$children的直接访问,以及bus总线通信的灵活应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vue通信应该是一个老生常谈的问题,面试也经常会有相关的问题,我之前作答往往是prop父传子,emit子传父,vuex复杂组件之间通信,bus全局通信如果不采用vue的通信方式我们还可以使用web存储(不推荐),自我感觉已经算很完美的回答了呀,现在想想可真的太无知了,今天详细介绍一下vue各种通信方式

1.prop、emit、vuex

上面几种通信都是最基础的建议移步vue官网查阅

2.provide和inject

provide和inject偏冷门的一个api可以跨层级通信,向下传递也就是说可用于给后辈传递信息

app

provide: {    title: "我是你爷爷组件"  },

chid或者grandChild

inject: ["title"]
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>provide-inject</title>
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>

<body>
    <div id="app" v-cloak>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    <script>
        let Child = {
            template: `<div>
                <span>子组建</span> 接收数据{{title}}  
            </div>`,
            // 可接收到Grandfather组件数据
            inject: ['title']
        }
        let Father = {
            template: `<div>{{name}}<Child/>{{title}}</div>`,
            data() {
                return {
                    name: '父组件'
                }
            },
            // 可接收到Grandfather组件数据
            inject: ['title'],
            components: {
                Child
            }
        }
        let Grandfather = {
            template: '<div><Father/></div>',
            provide: {
                title: '我是祖父组件'
            },
            components: {
                Father
            }
        }
        new Vue({
            el: '#app',
            template: `<div><Grandfather/>{{title}}</div>`,
            components: {
                Grandfather
            }
        })
    </script>
</body>

</html>

3.dispatch

根据获取$parent获取父级元素来通信

main.js

// dispatch从小往上传递数据
Vue.prototype.$dispatch = function (eventName, data) {  
  let parent = this.$parent 
   while (parent) { 
    parent.$emit(eventName, data)
    parent = parent.$parent  
  }
}

grandChild

<button @click="dispatch">通知父组件</button>
methods: {    
  dispatch() {
      this.$dispatch("dispatch", "来自孙子");    
  }  
}

app或child

 mounted() {    
  	this.$on("dispatch", grandChild => {      
      this.grandChild = grandChild;    
    }); 
  },

4.boardcast

根据获取$chidren向下查找传递数据
main.js

Vue.prototype.$boardcast = function (eventName, data) {  
  boardcast.call(this, eventName, data)
}
function boardcast(eventName, data) {  
    this.$children.forEach(child => {
      child.$emit(eventName, data)
      if (child.$children.length) {
        boardcast.call(child, eventName, data)
      }  
    });
}

grandChild或者child

<div style="color: yellow">boardcast{{msg}}</div>
mounted() {
  this.$on("boardcast", msg => {
    this.msg = msg;    
  });  
},

5.attrs和listeners

// 一级组件Home
<template>
  <div class="home">
    <h5>我是一级组件</h5>
    <img alt="Vue logo" src="../assets/logo.png" />
    <HelloWorld
      msg="Welcome to Your Vue.js App"
      :message="message"
      :messageChild="messageChild"
      @getTwoData="getTwoData"
      @getThreeData="getThreeData"
    />
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from "@/components/HelloWorld.vue";

export default {
  name: "home",
  components: {
    HelloWorld
  },
  data() {
    return {
      message: "传给二级组件",
      messageChild: "传给三级组件"
    };
  },
  methods: {
    getTwoData(val) {
      console.log("二级组件");
    },
    getThreeData(val) {
      console.log("三级组件");
    }
  }
};
</script>
// 二级组件 HelloWorld
<template>
  <div class="hello">
    <h5>我是二级组件</h5>
    <input type="text" v-model="helloVal" @input="listenData(helloVal)" />
    <!-- 三级组件中能直接触发getThreeData的原因在于 二级组件调用三级组件时 使用 v-on 绑定了$listeners 属性 -->
    <!-- 通过v-bind 绑定$attrs属性,三级组件可以直接获取到Home组件中传递下来的props(除了二级组件中props声明的) -->
    *<hello-child v-bind="$attrs" v-on="$listeners"></hello-child>*
  </div>
</template>

<script>
import HelloChild from "./HelloChild";
export default {
  name: "HelloWorld",
  data() {
    return {
      helloVal: this.message
    };
  },
  props: {
    msg: String,
    message: String // Home传递过来的数据
  },
  components: {
    "hello-child": HelloChild
  },
  methods: {
    listenData(val) {
      this.$emit("getTwoData", val);
    }
  }
};
</script>
// 三级组件HelloChild
<template>
  <div class="hello-child">
    <P>我是三级子组件</P>
    <input type="text" v-model="childVal" @input="listenChildVal(childVal)" />
    <input type="text" v-model="msg" />
    <!--无法获取HelloWorld组件中props声明后的message数据-->
  </div>
</template>
<script>
export default {
  props: {
    messageChild: String,
    message: String   // 无法获取HelloWorld组件中props声明后的message数据
  },
  data() {
    return {
      msg: this.message,
      childVal: this.messageChild
    };
  },
  methods: {
    listenChildVal(val) {
      this.$emit("getThreeData", val);
    }
  }
};
</script>
<style lang="less">
</style>

6.$parent

$children

在子组件中通过this.$parent获取父组件的方法和data数据,

在父组件中通过this.$children获取的是所有子组件

Vue.component("Child", {
	template: '<div>
	<div>{{childMsg}}</div>
	<button @click="changePrentData">改变父组件数据</button>
	</div>',
	data() {
		return {
			childMsg: '你好,我是子组件!'
		}
},
	method: {
		changePrentData() {
			this.$parent.msg = '更改父组件'
		}
	}
})
Vue.component("Parent", {
	template: '
	<div>
		<child/>
		<button @click="changePrentData">改变子组件件数据</button>
	</div>',
	data() {
		msg: "你好!"
	},
	method: {
		changePrentData() {
			this.$children[0].childMsg= '更改子组件'
		}
	}
})

7.bus(总线)通信

兄弟,父子,外甥都可以使用bus进行通信

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>bus兄弟组件通信</title>
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>

<body>
    <div id="app" v-cloak></div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    <script>
        // (bus)总线定义
        let bus = new Vue();
        let ComponentA = {
            template: `<div>
                    <button @click="sendB">给b组建传消息</button>                
                </div>`,
            methods: {
                sendB() {
                    bus.$emit('getA', '你好B,我是A')
                }
            }
        }
        // 接收a的消息
        let ChildB = {
            template: `<div> {{getaMsg}}</div>`,
            data() {
                return {
                    getaMsg: 'dssds'
                }
            },
            created() {
                bus.$on('getA', (val) => {
                    this.getaMsg = val
                    console.log(this)
                })
            },
        }
         // 接收a的消息
        let ComponentB = {
            template: `<div>
                    <span>{{valueA}}</span>
                    <ChildB/>
                </div>`,
            data() {
                return {
                    valueA: '1111'
                }
            },
            created() {
                // bus.$on('getA', (val) => {
                //     this.valueA = val
                //     console.log(this)
                // })
                let that = this
                bus.$on('getA', function(val) {
                    that.valueA = val
                })
            },
            components: {
                ChildB
            }
        }
         // 接收a的消息
        new Vue({
            el: '#app',
            template: `<div>
                    <ComponentA/>
                    <ComponentB/>
                    {{rootVal}}
                </div>`,
            data() {
                return {
                    rootVal: 'dsdsds'
                }
            },
            created() {
                let that = this
                bus.$on('getA', (val) => {
                    this.rootVal = val
                })
            },
            components: {
                ComponentB,
                ComponentA
            }
        })
    </script>
</body>

</html>

详细操作
https://github.com/cshuanglu/vue-communication.git

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值