通常在项目中,页面都是由很多个组件组成的,那么组件之间的通信(传值)我们该如何处理呢,我们通常采用如下方案处理:
父传子-Props
小细节:虽然理论上你也可以在向子组件传递 props 时使用驼峰形式(使用dom模板时例外),但实际上为了和 HTML attribute 对齐,我们通常会将其写为 kebab-case 形式
// 父组件
<template>
<MyComponent greeting-message="hello" />
</template>
// MyComponent.vue
<template>
<span>{{ greetingMessage }}</span>
</template>
<script setup lang=“ts”>
defineProps({
greetingMessage: String,
hello?: String // 这是配合ts的写法
// 配合校验+默认值
world: {
type: String,
required: true,
default: '100'
},
})
</script>
要记住,Props是单向数据流,切不可以直接改变它,如果我们需要对Props的值进行修改,可以尝试以下操作:
- 通过ref
const props = defineProps(['initialCounter'])
// 计数器只是将 props.initialCounter 作为初始值
// 像下面这样做就使 prop 和后续更新无关了
const counter = ref(props.initialCounter)
- 通过computed
const props = defineProps(['size'])
// 该 prop 变更时计算属性也会自动更新
const normalizedSize = computed(() => props.size.trim().toLowerCase())
子传父-emit
// 子组件MyButton.vue
<template>
<button @click="$emit('increaseBy', 1)">
Increase by 1
</button>
</template>
<script setup>
// 我们在setup中其实是没法直接使用$emit,需要引入defineEmits
import { defineEmits } from "vue";
// 这里定义emit事件的名称,比如上面click需要emit的方法,如下写法是等同于$emit('increaseBy', 1)
let emit = defineEmits(["increaseBy"]);
emit("increaseBy", 1)
<script>
// 父组件
<template>
<MyButton @increase-by="increaseCount" />
</template>
<script setup>
import { ref } from "vue";
let count = ref(0)
function increaseCount(n) {
count.value += n
}
</script>
嵌套组件-provide&inject
<!-- 在供给方组件内 -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('hello')
function updateLocation() {
location.value = 'word'
}
provide('location', {
location,
updateLocation
})
</script>
<!-- 在注入方组件 -->
<script setup>
import { inject } from 'vue'
// 这里接收的就是provide提供的值
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>
兄弟组件-mitt
在vue2中我们可以通过new一个Vue的实例来充当bus总线,vue3中变成了mitt,不过我们需要npm install mitt ---save。
// utils.js
import mitt from "mitt";
const bus = mitt();
export default bus
<!-- 在发布方 -->
<script setup>
// 这个路径不是固定写法,根据你项目决定
import bus from "@/utils"
bus.emit("emitFun", "你可能需要传递的数据")
</script>
<!-- 在接收方 -->
<script setup>
// 这个路径不是固定写法,根据你项目决定
import bus from "@/utils"
import { onMounted } from "vue";
onMounted(()=>{
// 第一个参数就是emit传递的第一个参数,是对应的
bus.on("emitFun", (params) => {
console.log(params); // "你可能需要传递的数据"
})
})
</script>