Vue2与Vue3的组件通讯对比
Vue2#
父传子#
父传子比较简单, 主要通过以下步骤实现
-
父在
template
中为子绑定属性<Child :childData='pMsg'/> <!-- 也可以写死 --> <Child childData='123'/> -
子用
props
接收数据,props
的值可以是数组或对象props: ["childData"] -
子在
template
中或其他地方任意使用接受到的数据<h2>我得到了{{childData}}</h2>
列出完整例子:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>title</title> </style> </head> <body> <div id="app">{{ message }}</div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> </body> </html>
Vue.component("Parent", { data() { return { pMsg: "小楼昨夜又东风", }; }, //步骤一 template: `<div><fieldset><legend>父组件</legend><input type="text" v-model="pMsg"/><Child :childData='pMsg'/></fieldset></div>`, }); Vue.component("Child", { //步骤三 template: `<div><fieldset><legend>子组件</legend>来自父组件的数据: {{ childData }}</fieldset></div>`, //步骤二 props: ["childData"], }); var vm = new Vue({ el: "#app", data() { return { msg: "往input中输入东西试试", }; }, template: `<div><fieldset><legend>App组件</legend>{{ msg }}<Parent/></fieldset></div>`, });
fieldset { margin-top: 30px; }
子传父#
- 父组件中为子组件绑定一个自定义事件
<h2> <Child @childHandler="childHandler" /></h2>` - 父组件中为自定义事件写函数,形参为要接收的值,假如要加到
this
中的话,最好在data
中预留一个key
methods: { childHandler(val) { this.ChildData = val } } - 子组件中绑定一个原生事件
再在方法中使用@input="change(data)" $emit
调用父组件中的方法
触发父组件中的自定义事件this.$emit("childHandler", val) $emit
: 触发当前实例上的事件。附加参数都会传给监听器回调
完整例子:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>title</title> </head> <body> <div id="app">{{ message }}</div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> </body> </html>
Vue.component("Parent", { data() { return { ChildData: "", }; }, //步骤一 template: `<div><fieldset><legend>父组件</legend><p>来自子组件的数据: {{ ChildData }}</p><Child @childHandler="childHandler" /></fieldset></div>`, // 步骤二 methods: { // 处理从子组件中获取的数据 childHandler(val) { this.ChildData = val; }, }, }); Vue.component("Child", { data() { return { data: "故国不堪回首月明中", }; }, //步骤三 template: `<div><fieldset><legend>子组件</legend><input type="text" v-model="data" @input="change(data)" /></fieldset></div>`, methods: { // 调用$emit方法 change(val) { this.$emit("childHandler", val); }, }, }); var vm = new Vue({ el: "#app", data() { return { msg: "在input中输入东西试试", }; }, template: `<div><fieldset><legend>App组件</legend>{{msg}}</h1><Parent/></fieldset></div>`, });
fieldset { margin-top: 30px; }
父传孙#
父组件里使用provide
, 子组件里使用inject
完整例子
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>title</title> </head> <body> <div id="app">{{ message }}</div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> </body> </html>
Vue.component("Parent", { data() { return { data: "小楼昨夜又东风" }; }, template: `<div><fieldset><legend>父组件</legend><p>父组件数据: {{ data }}</p><Child /></fieldset></div>`, // 步骤一 provide() { return { data: this.data, }; }, }); Vue.component("Child", { template: `<div><fieldset><legend>子组件</legend><GrandSon /></fieldset></div>`, }); Vue.component("GrandSon", { // 步骤二 // 接收祖辈的数据 data inject: ["data"], data() { return { // 通过this.x取值 parentData: this.data, }; }, template: `<div><fieldset><legend>孙组件</legend><p>祖辈的数据: {{ parentData }}</p></fieldset></div>`, }); var vm = new Vue({ el: "#app", data() { return { msg: "观察组件的数据", }; }, template: `<div><fieldset><legend>App组件</legend><p>{{ msg }}</p><Parent/></fieldset></div>`, });
fieldset { margin-top: 30px; }
注意, 这种方法传值不是响应数据
你可以把数据变为object类型, 让其可以同步修改
兄弟之间互传#
- 在Vue的原型对象向上添加一个属性叫
$bus
该属性是一个Vue
实例对象 - 发送端, 调用
this.$bus.$emit
- 接收端, 监听对应事件, 处理数据
完整例子:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>title</title> </head> <body> <div id="app">{{ message }}</div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> </body> </html>
// 步骤一 添加$bus属性 Vue.prototype.$bus = new Vue(); Vue.component("Child1", { data() { return { data: "小楼昨夜又东风" }; }, methods: { update() { // 步骤二 使用$emit触发自定义事件, 传入数据 this.$bus.$emit("handlerData", this.data); }, }, template: `<div><fieldset><legend>子组件</legend><p>子组件发送的数据: <input type="text" v-model="data" @input="update()"/></p></fieldset></div>`, }); Vue.component("Child2", { data() { return { data: "", }; }, mounted() { // 步骤三 处理传过来的数据 this.$bus.$on("handlerData", (val) => { this.data = val; }); }, template: `<div><fieldset><legend>子组件</legend><p>子组件接收的数据: {{ data }}</p></fieldset></div>` }); var vm = new Vue({ el: "#app", data() { return { msg: "往input中输入数据试试", }; }, template: `<div><fieldset><legend>App组件</legend><p>{{msg}}</p><Child1 /> <Child2 /></fieldset></div>`, });
fieldset { margin-top: 30px; }
Vue3#
由于vue3
将vue2
的选项变为了组合API, 而且把data
和methods
集合到了setup
中, 故而使用起来有所区别, 但也大差不差
父传子#
- 父组件使用
ref
或reactive
将数据变为响应数据 - 子组件使用
props
接收关于
props
见: props - 要在
setup
中使用, 使用如下方法:props: ["data"], setup(props, context) { props.data }
完整例子
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>title</title> </head> <body> <div id="app"> <fieldset> <legend>app组件</legend> {{ data }} <!-- 使用组件 --> <Parent /> </fieldset> </div> <script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script> </body> </html>
const AttributeBindingApp = { name: "App", setup() { const data = "往input中输入东西试试"; return { data, }; }, }; const app = Vue.createApp(AttributeBindingApp); app.component("Parent", { setup() { // 变为响应数据 const parentData = Vue.ref("故国不堪回首月明中"); return { parentData, }; }, template: `<fieldset><legend>父组件</legend> <input type="text" v-model="parentData" /> <Child :parentData="parentData" /></fieldset>`, }); app.component("Child", { props: ["parentData"], setup() { const childData = "childData"; return { childData, }; }, template: `<fieldset><legend>子组件</legend>{{ parentData }}</fieldset>`, }); app.mount("#app");
fieldset { margin-top: 30px; }
子传父#
- 父组件中定义接收数据的方法
- 在
template
中为子组件绑定自定义事件 - 在子组件中触发自定义事件, 执行
context.emit
方法 - 传给父组件使用
总的来说, 原理与Vue2差不多, 但由于要在
setup
中获取值, 故要使用参数接收
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>title</title> </head> <body> <div id="app"> <fieldset> <legend>app组件</legend> {{ data }} <!-- 使用组件 --> <Parent /> </fieldset> </div> <script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script> </body> </html>
const AttributeBindingApp = { name: "App", setup() { const data = "往input中输入东西试试"; return { data, }; }, }; const app = Vue.createApp(AttributeBindingApp); app.component("Parent", { setup(props, context) { const childData = Vue.ref(""); // 步骤一 定义处理接收数据的方法 const receive = (e) => { // 处理从子组件中传来的数据 childData.value = e; }; return { receive, childData, }; }, // 步骤二 自定义事件 触发处理接收数据的方法 template: `<fieldset><legend>父组件</legend><p>子组件中的数据: {{ childData }}</p><Child @inputText="receive" /></fieldset>`, }); app.component("Child", { props: ["parentData"], setup(props, context) { const data = Vue.ref("小楼昨夜又东风"); // 步骤四 调用context.emit const toParent = () => { // input时调用 // 调用inputText事件 context.emit("inputText", data.value); }; return { data, toParent, }; }, // 步骤三 触发事件 template: `<fieldset><legend>子组件</legend><input type="text" @input="toParent" v-model="data" /></fieldset>`, }); app.mount("#app");
fieldset { margin-top: 30px; }
父传孙#
和vue2一样, 同样使用
provide
和inject
但不同的是, 我们可以使用ref
和reactive
将数据转换为响应式数据
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>title</title> </head> <body> <div id="app"> <fieldset> <legend>app组件</legend> {{ data }} <!-- 使用组件 --> <Parent /> </fieldset> </div> <script src="https://unpkg.com/vue@3.2.26/dist/vue.global.js"></script> </body> </html>
const AttributeBindingApp = { name: "App", setup() { const data = "往两个input中都输入试试"; return { data, }; }, }; const app = Vue.createApp(AttributeBindingApp); app.component("Parent", { setup() { // 响应的数据 const data = Vue.ref(""); // 步骤一 使用provide // 把data 标记为 "parentData" Vue.provide("parentData", data); return { data, }; }, template: `<fieldset><legend>父组件</legend>从子孙辈中获取的数据: <input type="text" v-model="data" /> <Child /></fieldset>`, }); app.component("Child", { template: `<fieldset><legend>子组件</legend><GrandSon /></fieldset>`, }); app.component("GrandSon", { setup() { // 步骤二 接收数据 // 接收 parentData const data = Vue.inject("parentData"); return { data, }; }, template: `<fieldset><legend>孙组件</legend><p>从父辈中获取的数据: <input type="text" v-model="data" /></p></fieldset>`, }); app.mount("#app");
fieldset { margin-top: 30px; }
作者:忞翛
出处:https://www.cnblogs.com/lczmx/p/15708222.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
欢迎各位大佬评论交流。可以的话,不妨点一下推荐。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具