Vue中组件通信有哪些?它们分别用了什么方式传值?

418 阅读1分钟

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函数,并且设置形参接收子组件传递过来的实参

总结: 父自定义事件和方法, 等待子组件触发事件给方法传值

四、兄弟之间传递数据

image.png

核心语法

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先执行