Vue2与Vue3的组件通讯对比
Vue2
父传子
父传子比较简单, 主要通过以下步骤实现
父在
template
中为子绑定属性<Child :childData='pMsg'/>
<!-- 也可以写死 -->
<Child childData='123'/>
子用
props
接收数据,props
的值可以是数组或对象props: ["childData"]
子在
template
中或其他地方任意使用接受到的数据<h2>我得到了{{childData}}</h2>
列出完整例子:
<!--@html-start-->
<!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>
<!--@html-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
<!--@javascript-start-->
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>`,
});
<!--@javascript-end-->
子传父
- 父组件中为子组件绑定一个自定义事件
<h2> <Child @childHandler="childHandler" /></h2>`
- 父组件中为自定义事件写函数,形参为要接收的值,假如要加到
this
中的话,最好在data
中预留一个key
methods: {
childHandler(val) {
this.ChildData = val
}
}
- 子组件中绑定一个原生事件
@input="change(data)"
再在方法中使用
$emit
调用父组件中的方法this.$emit("childHandler", val)
触发父组件中的自定义事件
$emit
: 触发当前实例上的事件。附加参数都会传给监听器回调
完整例子:
<!--@html-start-->
<!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>
<!--@html-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
<!--@javascript-start-->
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>`,
});
<!--@javascript-end-->
父传孙
父组件里使用provide
, 子组件里使用inject
完整例子
<!--@html-start-->
<!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>
<!--@html-end-->
<!--@javascript-start-->
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>`,
});
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
注意, 这种方法传值不是响应数据
你可以把数据变为object类型, 让其可以同步修改
兄弟之间互传
- 在Vue的原型对象向上添加一个属性叫
$bus
该属性是一个Vue
实例对象 - 发送端, 调用
this.$bus.$emit
- 接收端, 监听对应事件, 处理数据
完整例子:
<!--@html-start-->
<!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>
<!--@html-end-->
<!--@javascript-start-->
// 步骤一 添加$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>`,
});
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
Vue3
由于vue3
将vue2
的选项变为了组合API, 而且把data
和methods
集合到了setup
中, 故而使用起来有所区别, 但也大差不差
父传子
- 父组件使用
ref
或reactive
将数据变为响应数据 - 子组件使用
props
接收
关于
props
见: props - 要在
setup
中使用, 使用如下方法:props: ["data"],
setup(props, context) {
props.data
}
完整例子
<!--@html-start-->
<!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>
<!--@html-end-->
<!--@javascript-start-->
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");
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
子传父
- 父组件中定义接收数据的方法
- 在
template
中为子组件绑定自定义事件 - 在子组件中触发自定义事件, 执行
context.emit
方法 - 传给父组件使用
总的来说, 原理与Vue2差不多, 但由于要在
setup
中获取值, 故要使用参数接收
<!--@html-start-->
<!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>
<!--@html-end-->
<!--@javascript-start-->
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");
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
父传孙
和vue2一样, 同样使用
provide
和inject
但不同的是, 我们可以使用ref
和reactive
将数据转换为响应式数据
<!--@html-start-->
<!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>
<!--@html-end-->
<!--@javascript-start-->
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");
<!--@javascript-end-->
<!--@css-start-->
fieldset {
margin-top: 30px;
}
<!--@css-end-->
Vue2与Vue3的组件通讯对比的更多相关文章
- 盘点Vue2和Vue3的10种组件通信方式(值得收藏)
Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异:本文将通过选项式API 组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式.其中将要实现的通信 ...
- vue2升级vue3:Vue Demij打通vue2与vue3壁垒,构建通用组件
如果你的vue2代码之前是使用vue-class-component 类组件模式写的.选择可以使用 https://github.com/facing-dev/vue-facing-decorator ...
- vue2.0中eventBus实现兄弟组件通讯
我们知道,在vue中父子组件的通讯是通过props和自定义事件搞定的,简单那的非父子组件通讯用bus(一个空的Vue实例),针对中大型的项目会选择vuex,然而小项目的话,便捷的解决方案就是event ...
- Vue2和Vue3技术整理1 - 入门篇 - 更新完毕
Vue2 0.前言 首先说明:要直接上手简单得很,看官网熟悉大概有哪些东西.怎么用的,然后简单练一下就可以做出程序来了,最多两天,无论Vue2还是Vue3,就都完全可以了,Vue3就是比Vue2多了一 ...
- vue2和vue3生命周期的区别
概念 首先,我们了解一下"生命周期"这个词.通俗的来说,生命周期就是一个事务从出生到消失的过程.例如,一个人从出生到去世.在vue中,vue的生命周期是指,从创建vue对象到销毁v ...
- vue2.x入坑总结—回顾对比angularJS/React的一统
从感性的角度讲,我是不屑于用VUE,觉得react套件用起来更顺手,但是vue现在越来火,所以也不得入vue(杂烩汤)的坑.vue/anguarJS/React,三者对关系现在就是: https:// ...
- Vue3 父组件调用子组件的方法
Vue3 父组件调用子组件的方法 // 父组件 <template> <div> 父页面 <son-com ref="sonRef"/> < ...
- vue2升级vue3:vue2 vue-i18n 升级到vue3搭配VueI18n v9
项目从vue2 升级vue3,VueI18n需要做适当的调整.主要是Vue I18n v8.x 到Vue I18n v9 or later 的变化,其中初始化: 具体可以参看:https://vue- ...
- vue2升级vue3指南(二)—— 语法warning&error篇
本文总结了vue2升级vue3可能会遇到的语法警告和错误,如果想知道怎样升级,可以查看我的上一篇文章:vue2升级vue3指南(一)-- 环境准备和构建篇 Warning 1.deep /deep/和 ...
随机推荐
- [atAGC045B]01 Unbalanced
将0变为-1后求前缀和,那么$s$的价值即为最大的前缀和-最小的前缀和(特别的,空前缀的前缀和为0) 令$f(x)$表示当最大的前缀和不大于$x$时,最小的前缀和最大是多少,答案即为$\min_{x} ...
- 测试平台系列(82) 解决APScheduler重复执行的问题
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上一节我们编写了在线执行R ...
- Redis 持久化方案
目录 持久化简介 什么是持久化? Redis 持久化方案 RDB RDB 简介 save 指令 操作与配置 工作原理 bgsave 指令 操作与配置 工作原理 bgsave 配置执行 相关配置 工作原 ...
- 网络协议之:一定要大写的SOCKS
目录 简介 SOCKS的故事 SOCKS的历史 SOCKS协议的具体内容 SOCKS4 SOCKS4a SOCKS5 总结 简介 很久很久以前,人们还穿的是草鞋,草鞋虽然穿着舒服,但是不够美观.然后人 ...
- NOI2020 同步赛划水记
因为太菜了没去现场参加 NOI 就算去了估计也只能混个Fe(雾) "两天都会各有一道签到题,争取拿到70分.剩下的题每道题打30分暴力.每天130分,就能稳拿Ag了."--ls D ...
- Codeforces 1010F - Tree(分治 NTT+树剖)
Codeforces 题面传送门 & 洛谷题面传送门 神仙题. 首先我们考虑按照这题的套路,记 \(t_i\) 表示 \(i\) 上的果子数量减去其儿子果子数量之和,那么对于一个合法的放置果子 ...
- Codeforces 497E - Subsequences Return(矩阵乘法)
Codeforces 题目传送门 & 洛谷题目传送门 一道还算不错的矩乘 tea 罢,不过做过类似的题应该就比较套路了-- 首先考虑对于一个固定的序列 \(\{a\}\) 怎样求其本质不同的序 ...
- 【R】调整ggplot图例大小
图例太多时,会挤压正图,显得正图展示区域很小,这时有必要缩小图例. ################# # 减小ggplot图例 ################# library(ggplot2) ...
- R语言与医学统计图形-【24】ggplot位置调整函数
ggplot2绘图系统--位置调整函数 可以参数position来调整,也有专门的函数position_*系列来设置. 位置函数汇总: 1.排列 并排排列 mean <- runif(12,1, ...
- Ubuntu16.04安装 2.8.5版本Ansible
wget https://bootstrap.pypa.io/pip/2.7/get-pip.py && python get-pip.py pip install --upgrade ...