Vue中组件通信有哪些?它们分别用了什么方式传值?
一、组件通信有三种方式:
1、父传子——父组件传给子组件
2、子传父——子组件传给父组件
3、兄弟之间传——同级组件相互传
二、父传子数据的方式:(动态属性)
方式一:
在父组件里,直接在子组件上添加v-for指令和自定义属性(动态属性)。
在子组件里,使用props属性接收父组件传递过来的数据,然后在template结构里使用插值表达式
方式二:父传给子的是一个item(对象)
App.vue
<template>
<div>
<h1>我是父元素</h1>
<!-- 第一种方式的结构 -->
<MyProduct
v-for="item in list"
:key="item.id"
:title="item.proname"
:price="item.proprice"
:info="item.info"
:item="item"
@getdataprice="getSondata"
></MyProduct>
<!-- 第二种方式的结构 -->
<!-- <MyProduct v-for="item in list" :key="item.id" :item="item"></MyProduct> -->
</div>
</template>
<script>
import MyProduct from './components/MyProduct.vue'
export default {
data() {
return {
list: [
{
id: 1,
proname: '超级好吃的棒棒糖',
proprice: 18.8,
info: '开业大酬宾, 全场8折',
},
{
id: 2,
proname: '超级好吃的大鸡腿',
proprice: 34.2,
info: '好吃不腻, 快来买啊',
},
{
id: 3,
proname: '超级无敌的冰激凌',
proprice: 14.2,
info: '炎热的夏天, 来个冰激凌了',
},
],
}
},
components: {
MyProduct,
},
methods: {
getSondata(idx, price) {
let index = this.list.findIndex((v) => v.id === idx)
this.list[index].proprice > 1 &&
(this.list[index].proprice = (
this.list[index].proprice - price
).toFixed(2))
},
},
}
</script>
<style scoped></style>
MyProduct.vue
<template>
<div class="my-product">
<!-- 第一种方式的结构 -->
<h3>标题:{{ title }}</h3>
<p>价格: {{ price }}元</p>
<p>{{ info }}</p>
<button @click="KanFn">砍价</button>
<!-- 第二种方式的结构 -->
<!-- 父传给子的是一个item(对象) -->
<!-- <h3>标题:{{ item.proname }}</h3>
<p>价格: {{ item.proprice }}元</p>
<p>{{ item.info }}</p> -->
</div>
</template>
<script>
export default {
// 第一种方式的结构
props: ['title', 'price', 'info', 'item'],
methods: {
KanFn() {
// 获取item的id值
let id = this.item.id
this.$emit('getdataprice', id, 1)
},
},
// 第二种方式的结构
// props: ['item'],
}
</script>
<style scoped>
.my-product {
width: 400px;
padding: 20px;
border: 2px solid #000;
border-radius: 5px;
margin: 10px;
}
</style>
三、子传父数据的方式——根据上面的案例实现
第一步骤:在子组件中,添加监听事件:<button @click="KanFn">砍价,然后在methods属性使用KanFn()函数,并且使用this.$emit()把子组件的数据传给父组件
第二步骤:父组件通过添加自定义事件(自定义事件的事件名是子组件的$emit方法中的第一个参数)接收子组件传来的参数。
做法:给MyProduct子组件添加自定义事件:如上面的案例中的@getdataprice="getSondata"接收子组件传递的数据,然后在methods属性中,使用getSondata函数,并且设置形参接收子组件传递过来的实参
总结: 父自定义事件和方法, 等待子组件触发事件给方法传值
四、兄弟之间传递数据
核心语法
EventBus/index.js
- 定义事件总线bus对象
import Vue from 'vue'
// 导出空白vue对象
export default new Vue()
List.vue
注册事件 - 等待接收要砍价的值 (==EventBus接收方==)
<template>
<ul class="my-product">
<li v-for="(item, index) in arr" :key="index">
<span>{{ item.proname }}</span>
<span>{{ item.proprice }}</span>
</li>
</ul>
</template>
<script>
// 目标: 跨组件传值
// 1. 引入空白vue对象(EventBus)
// 2. 接收方 - $on监听事件
import eventBus from "../EventBus";
export default {
props: ["arr"],
// 3. 组件创建完毕, 监听send事件
created() {
eventBus.$on("send", (index, price) => {
this.arr[index].proprice > 1 &&
(this.arr[index].proprice = (this.arr[index].proprice - price).toFixed(2));
});
},
};
</script>
<style scoped>
.my-product {
width: 400px;
padding: 20px;
border: 2px solid #000;
border-radius: 5px;
margin: 10px;
}
</style>
components/MyProduct_sub.vue(==主要写触发eventBus身上事件==)
<template>
<div class="my-product">
<h3>标题: {{ title }}</h3>
<p>价格: {{ price }}元</p>
<p>{{ intro }}</p>
<button @click="subFn">宝刀-砍1元</button>
</div>
</template>
<script>
import eventBus from '../EventBus'
export default {
props: ['index', 'title', 'price', 'intro'],
methods: {
subFn(){
this.$emit('subprice', this.index, 1) // 子向父
eventBus.$emit("send", this.index, 1) // 跨组件
}
}
}
</script>
<style scoped>
.my-product {
width: 400px;
padding: 20px;
border: 2px solid #000;
border-radius: 5px;
margin: 10px;
}
</style>
总结: 空的Vue对象, 只负责$on
注册事件, $emit
触发事件, 一定要确保$on
先执行