Vue 3 组件通信教程

ops/2024/11/30 9:13:14/

Vue 3 组件通信教程

1. Props 父传子

1.1 基础用法

在 Vue 3 中,我们使用 defineProps 来声明组件的 props:

<!-- 子组件 ChildComponent.vue -->
<script setup>
const props = defineProps({message: String,count: {type: Number,required: true,default: 0},items: {type: Array,default: () => []}
})
</script><template><div><p>{{ message }}</p><p>Count: {{ count }}</p></div>
</template>

父组件中使用:

<!-- 父组件 ParentComponent.vue -->
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'const parentMessage = ref('Hello from parent')
const parentCount = ref(42)
</script><template><ChildComponent :message="parentMessage":count="parentCount"/>
</template>

1.2 Props 验证

Props 可以设置详细的验证规则:

<script setup>
const props = defineProps({// 基础类型检查propA: Number,// 多种类型propB: [String, Number],// 必填字段propC: {type: String,required: true},// 带有默认值propD: {type: Number,default: 100},// 带有默认值的对象propE: {type: Object,default: () => ({ message: 'hello' })},// 自定义验证函数propF: {validator(value) {return ['success', 'warning', 'danger'].includes(value)}}
})
</script>

2. Emits 子传父

2.1 基础用法

使用 defineEmits 声明事件:

<!-- 子组件 ChildComponent.vue -->
<script setup>
const emit = defineEmits(['update', 'delete'])const handleClick = () => {emit('update', { id: 1, data: 'new value' })
}
</script><template><button @click="handleClick">更新数据</button>
</template>

父组件中接收事件:

<!-- 父组件 ParentComponent.vue -->
<script setup>
import ChildComponent from './ChildComponent.vue'const handleUpdate = (payload) => {console.log('收到更新:', payload)
}
</script><template><ChildComponent @update="handleUpdate" />
</template>

2.2 带验证的 Emits

<script setup>
const emit = defineEmits({// 不带验证函数click: null,// 带验证函数submit: (payload) => {if (!payload.email) {return false}return true}
})
</script>

3. v-model 双向绑定

3.1 基础用法

<!-- 子组件 CustomInput.vue -->
<script setup>
defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script><template><input:value="modelValue"@input="emit('update:modelValue', $event.target.value)"/>
</template>

父组件中使用:

<script setup>
import { ref } from 'vue'
import CustomInput from './CustomInput.vue'const text = ref('')
</script><template><CustomInput v-model="text" /><p>输入的内容:{{ text }}</p>
</template>

3.2 多个 v-model 绑定

<!-- 子组件 UserForm.vue -->
<script setup>
defineProps(['firstName', 'lastName'])
const emit = defineEmits(['update:firstName', 'update:lastName'])
</script><template><input:value="firstName"@input="emit('update:firstName', $event.target.value)"/><input:value="lastName"@input="emit('update:lastName', $event.target.value)"/>
</template>

父组件使用:

<script setup>
import { ref } from 'vue'
import UserForm from './UserForm.vue'const firstName = ref('')
const lastName = ref('')
</script><template><UserFormv-model:firstName="firstName"v-model:lastName="lastName"/>
</template>

4. provide/inject 依赖注入

4.1 基础用法

<!-- 父组件提供数据 -->
<script setup>
import { provide, ref } from 'vue'const theme = ref('dark')
provide('theme', theme)
</script><!-- 子组件注入数据 -->
<script setup>
import { inject } from 'vue'const theme = inject('theme', 'light') // 第二个参数是默认值
</script>

4.2 响应式数据注入

<!-- 父组件 -->
<script setup>
import { provide, ref, readonly } from 'vue'const count = ref(0)
const incrementCount = () => {count.value++
}// 提供只读值和修改方法
provide('count', readonly(count))
provide('increment', incrementCount)
</script><!-- 子组件 -->
<script setup>
import { inject } from 'vue'const count = inject('count')
const increment = inject('increment')
</script><template><button @click="increment">{{ count }}</button>
</template>

5. EventBus 事件总线

虽然 Vue 3 移除了内置的事件总线,但我们可以使用第三方库或自己实现一个简单的事件总线:

// eventBus.js
import mitt from 'mitt'
export default mitt()

使用示例:

<!-- 组件 A -->
<script setup>
import eventBus from './eventBus'const sendMessage = () => {eventBus.emit('custom-event', { message: 'Hello!' })
}
</script><!-- 组件 B -->
<script setup>
import { onMounted, onUnmounted } from 'vue'
import eventBus from './eventBus'const handleEvent = (data) => {console.log(data.message)
}onMounted(() => {eventBus.on('custom-event', handleEvent)
})onUnmounted(() => {eventBus.off('custom-event', handleEvent)
})
</script>

6. refs 直接访问

6.1 模板引用

<!-- 父组件 -->
<script setup>
import { ref, onMounted } from 'vue'
import ChildComponent from './ChildComponent.vue'const childRef = ref(null)onMounted(() => {// 访问子组件的方法或属性childRef.value.someMethod()
})
</script><template><ChildComponent ref="childRef" />
</template><!-- 子组件 -->
<script setup>
// 需要显式暴露方法给父组件
defineExpose({someMethod() {console.log('方法被调用')}
})
</script>

最佳实践建议

  1. 优先使用 props 和 emits 进行父子组件通信
  2. 对于跨多层组件的通信,考虑使用 provide/inject
  3. 对于全局状态管理,使用 Vuex 或 Pinia
  4. 避免过度使用 EventBus,它可能导致维护困难
  5. 谨慎使用 refs 直接访问子组件,这可能破坏组件封装性

注意事项

  1. Props 是只读的,不要在子组件中直接修改
  2. 使用 v-model 时注意命名冲突
  3. provide/inject 的响应式数据建议使用 readonly 包装
  4. 在组件卸载时记得清理事件监听器
  5. 使用 TypeScript 时,建议为 props 和 emits 添加类型声明

http://www.ppmy.cn/ops/137888.html

相关文章

激光雷达定位与建图-拟合问题

本篇文章介绍如何在点云中提取线段和平面。 一、平面拟合 1. 问题提出 给定一组由N个点组成的点云 X { x 1 , ⋯ , x n } X \left \{x_{1}, \cdots , x_{n} \right \} X{x1​,⋯,xn​} ,其中每个点取三维欧式坐标 x k x_{k} xk​&#xff0c;寻找一组平面参数n&#xff0c;…

人工智能如何改变你的生活?

在我们所处的这个快节奏的世界里&#xff0c;科技融入日常生活已然成为司空见惯的事&#xff0c;并且切实成为了我们生活的一部分。在这场科技变革中&#xff0c;最具变革性的角色之一便是人工智能&#xff08;AI&#xff09;。从我们清晨醒来直至夜晚入睡&#xff0c;人工智能…

原型模式

功能&#xff1a;复制一个运行时的对象&#xff0c;包括对象各个成员当前的值。并且能够通过父类的指针来克隆出子类的对象 主要解决&#xff1a;在运行期建立原型 优点&#xff1a;性能提高、避免了构造函数的约束 步骤&#xff1a; 1、定义抽象原型&#xff0c;声明纯虚接…

C# 可空类型

文章目录 前言一、单问号&#xff08;?&#xff09;二、双问号&#xff08;??&#xff09; 前言 可空类型&#xff08;Nullable&#xff09;是一个极具实用性的特性&#xff0c;它为我们处理那些可能出现未赋值情况的数据提供了便捷且合理的方式。而其中&#xff0c;单问号&…

如何使用 Codegen 加速 React Native 开发?

写在前面 在 React Native 开发中&#xff0c;经常需要编写大量的样板代码&#xff0c;例如组件、屏幕、API 等。这些重复性的工作不仅浪费时间&#xff0c;还容易出错。为了解决这个问题&#xff0c;Facebook 推出了一个名为 Codegen 的工具&#xff0c;它可以根据模板和配置…

海盗王用golang重写的AccountServer功能

自从用golang重写了海盗王的网关gateserver以来&#xff0c;一直想把accountserver也重写了&#xff0c;但是一直没有进行。 趁上次刚写好那个golang版的更新器&#xff0c;还有些熟悉&#xff0c;于是把原来AccountServer的C代码重写读了个大概。它原版的写得太过于复杂&#…

【目标跟踪】Anti-UAV数据集详细介绍

Anti-UAV数据集是在2021年公开的专用于无人机跟踪的数据集&#xff0c;该数据集采用RGB-T图像对的形式来克服单个类型视频的缺点&#xff0c;包含了318个视频对&#xff0c;并提出了相应的评估标准&#xff08;the state accurancy, SA)。 文章链接&#xff1a;https://arxiv.…

宝塔Linux面板上传PHP文件或者修改PHP文件,总是转圈圈,其他文件正常,解决办法

目录 问题描述 寻找解决方案 1.重启宝塔面板 2.清理宝塔缓存 3.升级面板 4.ssh远程 5.清空回收站 6.换网络 7. IDE远程编辑 总结&#xff1a; 问题描述 一直用宝塔linux面板&#xff0c;感觉非常好用&#xff0c;点点就能搞定&#xff0c;环境也很好配置。 公司搬家&…