本文采用的编写方式,比options API更自由,vue3中常用的7种组件通讯方式:
props
emit
v-model
refs
provide/inject
eventBus
vuex/pinia
1、Props:
父组件代码如下:
-
- <child-components :list="list">child-components>
-
- <div class="child-wrap input-group">
- <input
- v-model="value"
- type="text"
- class="form-control"
- placeholder="Please enter"
- />
- <div class="input-group-append">
- <button @click="handleAdd" class="btn btn-primary" type="button">
- add
- button>
- div>
- div>
- <script setup>
- import { ref } from 'vue'
- import ChildComponents from './child.vue'
- const list = ref(['JavaScript', 'HTML', 'CSS'])
- const value = ref('')
- // event handling function triggered by add
- const handleAdd = () => {
- list.value.push(value.value)
- value.value = ''
- }
- script>
子组件只需要渲染父组件传递的值,代码如下:
-
- <ul class="parent list-group">
- <li class="list-group-item" v-for="i in props.list" :key="i">{{ i }}li>
- ul>
- <script setup>
- import { defineProps } from 'vue'
- const props = defineProps({
- list: {
- type: Array,
- default: () => [],
- },
- })
- script>
2、Emit:
父组件代码如下:
-
-
- <ul class="parent list-group">
- <li class="list-group-item" v-for="i in list" :key="i">{{ i }}li>
- ul>
-
- <child-components @add="handleAdd">child-components>
- <script setup>
- import { ref } from 'vue'
- import ChildComponents from './child.vue'
- const list = ref(['JavaScript', 'HTML', 'CSS'])
- // event handling function triggered by add
- const handleAdd = value => {
- list.value.push(value)
- }
- script>
我们在父组件中定义列表,子组件只需要传递添加的值,子组件代码如下:
-
- <div class="child-wrap input-group">
- <input
- v-model="value"
- type="text"
- class="form-control"
- placeholder="Please enter"
- />
- <div class="input-group-append">
- <button @click="handleSubmit" class="btn btn-primary" type="button">
- add
- button>
- div>
- div>
- <script setup>
- import { ref, defineEmits } from 'vue'
- const value = ref('')
- const emits = defineEmits(['add'])
- const handleSubmit = () => {
- emits('add', value.value)
- value.value = ''
- }
- script>
点击子组件中的【添加】按钮后,我们会发出一个自定义事件,并将添加的值作为参数传递给父组件。在父组件中,只需要监听子组件的自定义事件,然后执行相应的添加逻辑即可。
3、v-model:
父组件代码如下:
-
-
- <ul class="parent list-group">
- <li class="list-group-item" v-for="i in list" :key="i">{{ i }}li>
- ul>
-
- <child-components v-model:list="list">child-components>
- <script setup>
- import { ref } from 'vue'
- import ChildComponents from './child.vue'
- const list = ref(['JavaScript', 'HTML', 'CSS'])
- script>
子组件代码如下:
- <div class="child-wrap input-group">
- <input
- v-model="value"
- type="text"
- class="form-control"
- placeholder="Please enter"
- />
- <div class="input-group-append">
- <button @click="handleAdd" class="btn btn-primary" type="button">
- add
- button>
- div>
- div>
- <script setup>
- import { ref, defineEmits, defineProps } from 'vue'
- const value = ref('')
- const props = defineProps({
- list: {
- type: Array,
- default: () => [],
- },
- })
- const emits = defineEmits(['update:list'])
- // Add action
- const handleAdd = () => {
- const arr = props.list
- arr.push(value.value)
- emits('update:list', arr)
- value.value = ''
- }
- script>
在子组件中,我们先定义props和emits,添加完成后再发出指定的事件。注意:update:*是Vue中固定的写法,*代表props中的一个属性名。
4、Refs:
父组件代码如下:
-
- <ul class="parent list-group">
- <li class="list-group-item" v-for="i in childRefs?.list" :key="i">
- {{ i }}
- li>
- ul>
-
- <child-components ref="childRefs">child-components>
-
- <script setup>
- import { ref } from 'vue'
- import ChildComponents from './child.vue'
- const childRefs = ref(null)
- script>
子组件代码如下:
- <div class="child-wrap input-group">
- <input
- v-model="value"
- type="text"
- class="form-control"
- placeholder="Please enter"
- />
- <div class="input-group-append">
- <button @click="handleAdd" class="btn btn-primary" type="button">
- add
- button>
- div>
- div>
- <script setup>
- import { ref, defineExpose } from 'vue'
- const list = ref(['JavaScript', 'HTML', 'CSS'])
- const value = ref('')
- // event handling function triggered by add
- const handleAdd = () => {
- list.value.push(value.value)
- value.value = ''
- }
- defineExpose({ list })
- script>
注意:默认情况下,setup 组件是关闭的,通过模板 ref 获取组件的公共实例。如果需要公开,需要通过defineExpose API 公开。
5、provide/inject:
父组件代码如下:
-
-
- <child-components>child-components>
-
- <div class="child-wrap input-group">
- <input
- v-model="value"
- type="text"
- class="form-control"
- placeholder="Please enter"
- />
- <div class="input-group-append">
- <button @click="handleAdd" class="btn btn-primary" type="button">
- add
- button>
- div>
- div>
- <script setup>
- import { ref, provide } from 'vue'
- import ChildComponents from './child.vue'
- const list = ref(['JavaScript', 'HTML', 'CSS'])
- const value = ref('')
- // Provide data to child components.
- provide('list', list.value)
- // event handling function triggered by add
- const handleAdd = () => {
- list.value.push(value.value)
- value.value = ''
- }
- script>
子组件代码如下:
-
- <ul class="parent list-group">
- <li class="list-group-item" v-for="i in list" :key="i">{{ i }}li>
- ul>
- <script setup>
- import { inject } from 'vue'
- // Accept data provided by parent component
- const list = inject('list')
- script>
注意:使用 provide 进行数据传输时,尽量使用 readonly 封装数据,避免子组件修改父组件传递的数据。
6、eventBus:
Vue 3 中移除了 eventBus,但可以借助第三方工具来完成。Vue 官方推荐使用 mitt 或 tiny-emitter,这里讲解 mitt:
先安装npm i mitt,然后再main.js内全局引用:
- // main.js
- import { createApp } from 'vue'
- import App from './App.vue'
- const app = createApp(App)
- import mitt from 'mitt'
- app.config.globalProperties.$bus= mitt();// 主要是这行
父组件代码如下:
- <div>
- <h1>mitt事件总线h1>
- <Child1 />
- div>
- <script setup>
- import Child1 from./Child1.vue
- const { proxy } = getCurrentInstance();
- const msg=ref('');
- //接收数据
- proxy.$bus.on('cat', data => {
- msg.value=data
- })
- script>
- <style lang-"scss"scoped>style>
子组件代码如下:
- <div>
- <h3>子组件1h3>
- <button @click="sendMsg”>发送事件