1、props
props是Vue中最常见的父子通信方式,使用起来也方便。
使用方法:
import { defineProps } from "vue";
const props = defineProps({
list: {
type: Array,
default: () => [],
}
});
// 属性的使用
console.log(props.list);
2、emit
emit是子组件向父组件传递数据
父组件:
@eventChange="handleChange"
子组件:
import { defineEmits } from "vue";
const emits = defineEmit(["eventChange"]);
const arr = [];
const handleAdd = () => {
emits("eventChange", arr);
};
3、v-model
v-model 是 Vue 中一个优秀的语法糖,如下图代码:
父组件:
<div v-model:title="title"></div>
注意:如果想在子组件里面使用emit("update:title", title)的方式修改title时,此处的v-model:title则不能缩写为:title,否则title的值不会发生变化
子组件:
<template>
<div class="child-wrap input-group">
<div class="input-group-append">
<button @click="clickEvent" class="btn btn-primary" type="button">
add
</button>
</div>
</div>
</template>
<script setup>
import { defineEmits, defineProps } from 'vue';
const props = defineProps({
title: {
type: String,
default: "",
},
});
const emits = defineEmits(['update:title']);
const clickEvent = () => {
const newTitle = props.title;
emits('update:title', newTitle);
};
</script>
注意:update:*是Vue中固定的写法,*代表props中的一个属性名。
4、ref与$parent
ref:用于父组件操作子组件数据或者方法
$parent:用于子组件操作父组件数据或者方法
注意:两者相互操作的前提条件是必须使用defineExpose暴露自身的数据及方法
使用API选项时,可以通过this.$refs.name获取指定元素或组件 (Vue2或非组合式API适用)
组合API,需要定义一个ref对象,且声明的遍历需要与声明的ref对象名一致,如图所示:
// 父组件
<template>
<ul class="parent list-group" v-if="!!childRefs.list">
<li class="list-group-item" v-for="i in childRefs.list" :key="i">
{{ i }}
</li>
</ul>
<button @click="handleClick"></button>
<!-- The value of the child component ref is the same as that in the <script> -->
<child-components ref="childRefs"></child-components>
</template>
<script setup>
import { ref, watch } from 'vue';
import ChildComponents from './child.vue';
// 需要声明与ref同名的遍历"childRefs"
const childRefs = ref(null);
// 通过父组件修改子组件的值
const handleClick = () => {
childRefs.clickEvent();
};
</script>
// 子组件
<template>
<div class="child-wrap input-group">
<div class="input-group-append">
<button @click="clickEvent" class="btn btn-primary" type="button">
add
</button>
</div>
</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue';
const list = ref(['JavaScript', 'HTML', 'CSS']);
// event handling function triggered by add
const clickEvent = () => {
list.value.push(value.value)
};
// 暴露子组件的值给父组件使用,但这个是同步的,目前还不清楚如果改变list值的时候,父组件是如何监听值的变化
defineExpose({
list,
clickEvent,
});
</script>
5、provide/inject
provide/inject是 Vue 中提供的一对 API。无论层级多深,API 都可以实现父组件到子组件的数据传递。
父组件代码如下:
<template>
<!-- child component -->
<child-components></child-components>
<!-- parent component -->
<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>
</template>
<script setup>
import { ref, provide } from 'vue';
import ChildComponents from './child.vue';
const list = ref(['JavaScript', 'HTML', 'CSS']);
const value = ref('');
// 父组件提供键值对
provide('list', list.value);
const handleAdd = () => {
list.value.push(value.value);
value.value = '';
};
子组件代码如下:
<template>
<ul class="parent list-group">
<li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
</ul>
</template>
<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 或 vue3-mitt 或 tiny-emitter。
emitter的全局引入:
// 引入mitt第三方插件
import mitt from "mitt";
// 调用插件
const emitter = mitt();
// 暴露emitter方法,放置到全局里面
export { emitter };
emitter的使用:
// 发布的事件回调
function handleEvent = (param) => {
// 发布需要操作的逻辑代码
console.log("需要操作的逻辑");
};
// emitter的事件订阅
emitter.on("public", handleEvent);
// emitter事件的注销
emitter.off("public", handleEvent);
/**
* emitter事件的发布
* param:需要传递的参数
*/
emitter.emit("public", param);
7、vuex/pinia
Vuex 和 Pinia 是 Vue 3 中的状态管理工具,使用这两个工具可以轻松实现组件通信。由于这两个工具都比较强大,这里就不一一展示了。有关详细信息,请参阅文档。
相关内容参考自:7个 Vue 3 中的组件通信方式 (qq.com)