深入了解vue中的部分组件通信

436 阅读5分钟

前言

在Vue.js中,组件通信是指在不同的Vue组件之间传递数据或触发事件的过程。Vue提供了多种方式来实现组件之间的通信,主要包括以下几种:

父子组件通信

通过props传递数据

image.png

  • 通过在子组件的标签上定义属性,父组件可以将数据传递给子组件。
  • 在子组件中使用props选项接收父组件传递的数据。

如下面的例子:

1. App2.vue

template部分:

<template>
  <div class="head">
    <!-- 输入框绑定到 message 数据 -->
    <input type="text" v-model="message" />
    
    <!-- 点击按钮触发 submit 方法 -->
    <button @click="submit">确定</button>
  </div>

  <!-- 引用 List 组件并通过属性传递 lists 数据 -->
  <List :lists="lists" />
</template>

script部分:

<script>
import List from "./components/body2/list.vue";
export default {
  components: {
    List,
  },
  data() {
    return {
      lists: ["html", "css"],
      message: "",
    };
  },
  methods: {
    submit() {
      // 当点击确定按钮时,将输入框的内容添加到 lists 数组中
      if (this.message) {
        this.lists.push(this.message);
        this.message = "";
      }
    },
  },
};
</script>

App2.vue组件中,通过使用v-model将输入框和message数据进行双向绑定。当用户在输入框中输入内容时,message数据会同步更新。当点击确定按钮时,通过调用submit方法,将message的内容添加到lists数组中。

2. list.vue

template部分:

<template>
  <div class="body">
    <ul>
      <!-- 使用 v-for 遍历 lists 数组,动态生成列表项 -->
      <li v-for="item in lists" :key="item">{{ item }}</li>
    </ul>
  </div>
</template>

script部分:

<script>
export default {
  // 通过 props 接收父组件传递过来的 lists 数组
  props: ['lists'],
};
</script>

list.vue组件中,通过使用props属性接收父组件传递的lists数组。这样,list.vue组件就可以在自己的模板中使用这个来自父组件的数据,实现了组件之间的传值。

在上述代码中,是通过在父组件中使用props将数据传递给子组件,以及在子组件中使用v-model实现双向数据绑定,实现了组件之间的传值。这样,App2.vue中的输入框的内容能够更新到list.vue中的列表中。但需要注意的是:因为props属性是单向数据流,只能从父组件流向子组件,不能反过来。注意不要去尝试修改props属性的值,即使改了也不会影响到父组件的值。

既然有了父子组件传值,那么自然也就有子父组件传值了

子父组件传值(也可以称为自定义事件): $emit

  • 子组件可以通过$emit方法触发自定义事件,并传递数据给父组件。
  • 在父组件中使用v-on(也就是@)监听子组件的自定义事件。

如下面的例子:

1. App3.vue

template部分:

<template>
  <!-- 引用 Header 组件并通过监听 add 事件调用 handle 方法 -->
  <Header @add="handle" />

  <div class="body">
    <ul>
      <!-- 使用 v-for 遍历 lists 数组,动态生成列表项 -->
      <li v-for="(item, index) in lists" :key="(item, index)">{{ item }}</li>
    </ul>
  </div>
</template>

script部分:

<script>
import Header from './components/body3/header.vue';
export default {
  components: {
    Header
  },
  data() {
    return {
      lists: ["html", "css"],
      message: "",
    };
  },
  methods: {
    handle(val) {
      // 接收来自 Header 组件触发的 add 事件,将数据添加到 lists 数组中
      console.log(val);
      this.lists.push(val);
    }
  }
};
</script>

App3.vue组件中,通过在Header组件的标签上监听自定义事件add,并调用handle方法来接收来自Header组件的数据。这样,就实现了子组件(Header)向父组件(App3.vue)传递数据的功能。

2. header.vue

template部分:

<template>
   <div class="head">
    <!-- 输入框绑定到 message 数据 -->
    <input type="text" v-model="message">
    
    <!-- 点击按钮触发 submit 方法 -->
    <button @click="submit">确定</button>
  </div>
</template>

script部分:

<script>
export default {
  data() {
    return {
      message: ''
    }
  },
  methods: {
    submit() {
      // 触发自定义事件 add,将 message 数据传递给父组件
      this.$emit('add', this.message);
      this.message = ''; // 清空输入框内容
    }
  }
}
</script>

header.vue组件中,当用户点击确定按钮时,通过this.$emit触发了自定义事件add,并传递了message数据给父组件。这样,header.vue组件就向父组件(App3.vue)传递了数据。

上述代码通过自定义事件实现了子组件(header.vue)向父组件(App3.vue)传递数据的功能。当在输入框中输入内容并点击确定按钮时,将数据传递给父组件,父组件接收到数据并将其添加到lists数组中,实现了组件之间的传值。

兄弟组件通信

兄弟组件之间的通信通常通过它们共同的父组件来实现。兄弟组件通过将数据传递给父组件,再由父组件将数据传递给另一个兄弟组件来完成通信。在实现兄弟组件通信时,我们需要借助vuex来实现。我们需要在终端中使用 npm install vuex --save来下载vuex的包。并在src下创建一个命名为store的文件夹来充当仓库的角色,借此来实现兄弟组件之间的通信。

vuex

  • Vuex是Vue.js官方提供的状态管理库,用于在不同组件之间共享状态。
  • 组件可以通过提交(mutations)或分发(actions)来改变共享状态。
  • state用来存放共享变量的地方
  • getter,可以增加一个getter派生状态,(相当于store中的计算属性),用来获得共享变量的值
  • mutations用来存放修改state的方法。
  • actions也是用来存放修改state的方法,不过action是在mutations的基础上进行。常用来做一些异步操作

image.png

如下面的例子:

1. App4.vue

template部分:

<template>
  <div>
    <!-- 引用 Header 组件 -->
    <Header />
    
    <!-- 引用 List 组件 -->
    <List />
  </div>
</template>

script部分:

<script>
import Header from './components/body4/header.vue'
import List from './components/body4/list.vue'
export default {
  components: {
    Header,
    List
  }
}
</script>

App4.vue组件中,引用了两个子组件 HeaderList

2. header.vue 组件

template部分:

<template>
  <div class="head">
    <!-- 输入框绑定到 message 数据 -->
    <input type="text" v-model="message" />
    
    <!-- 点击按钮触发 submit 方法 -->
    <button @click="submit">确定</button>
  </div>
</template>

script部分:

<script>
import { mapMutations } from 'vuex'

export default {
  data() {
    return {
      message: ''
    };
  },
  methods: {
    ...mapMutations(['addLists']),
    submit() {
      // 将 message 存入 Vuex 仓库中
      this.addLists(this.message);
    }
  }
};
</script>

header.vue组件中,使用 Vuex 的 mapMutations 辅助函数,映射了一个名为 addLists 的 mutation。当用户在输入框中输入内容并点击确定按钮时,通过调用 submit 方法触发 addLists mutation 将 message 存入 Vuex 仓库。

3. list.vue 组件

template部分:

<template>
  <div class="body">
    <ul>
      <!-- 使用 v-for 遍历 lists 数组,动态生成列表项 -->
      <li v-for="(item, index) in lists" :key="(item, index)">{{ item }}</li>
    </ul>
  </div>
</template>

script部分:

<script>
import { mapState } from "vuex";

export default {
  computed: {
    ...mapState(['lists']),
  }
};
</script>

list.vue组件中,使用 Vuex 的 mapState 辅助函数,映射了一个名为 lists 的状态。这样,list.vue组件就可以在自己的模板中使用 lists 状态,实现了组件之间的传值。lists 数组来自 Vuex 仓库,它会在仓库中随着 addLists中的 mutation 的执行而更新。

通过上述例子,我们使用 Vuex 实现了 (header.vue) 组件将数据存入仓库,(list.vue) 组件从仓库中获取数据的过程,实现了组件之间的传值。

结语

父子关系的组件数据传递可以选择 props  与 $emit进行传递 兄弟组件则可以选择使用vuex来实现数据的传递。 但实际上组件之间的通信都可以使用vuex来实现,但是在实际应用中还是要根据项目的需求和架构来选择合适的组件通信方式。