Vue的props和emits -- 组件通信

props和emits之间的组件通信

数据流向

  • props:父组件 → 子组件(数据下行)
  • emit:子组件 → 父组件(事件上行)

核心机制

  • props:父组件通过属性传递数据给子组件
  • emit:子组件通过事件向父组件发送消息

设计模式

单向数据流

父组件 --props--> 子组件 --emit--> 父组件

完美配合

  • props 传递状态数据
  • emit 通知状态变更
  • 共同实现可复用、可维护的组件化架构

这就是Vue组件间通信的基础模式!



分项解释

分项解释1 - Props

在Vue中,props(属性) 是父组件向子组件传递数据的自定义属性。

主要特点:

  • 单向数据流:数据只能从父组件流向子组件,子组件不能直接修改props
  • 可配置性:可以定义类型验证、默认值、是否必需等
  • 组件通信:实现父组件与子组件的数据传递

示例:

<!-- 子组件 -->
<script setup>
defineProps({
  title: String,
  count: {
    type: Number,
    default: 0
  }
})
</script>

<!-- 父组件使用 -->
<ChildComponent title="Hello" :count="5" />

props使得Vue组件可以复用并接收不同的数据,是组件化开发的核心概念之一。


分项解释2 - Emits

在Vue中,emit(发射) 是子组件向父组件传递消息的方法。

主要特点:

  • 子传父:子组件通过事件通知父组件
  • 触发父组件方法:父组件可以监听子组件发出的事件并执行相应逻辑
  • 可传递数据:可以携带数据传递给父组件

示例:

<!-- 子组件 -->
<script setup>
// 1. 定义emit函数(获取发射事件的能力) - emit(事件名称, 传递的数据)
const emit = defineEmits(['update'])

function handleClick() {
  // 2. 使用emit函数来发射事件
  emit('update', newValue)  // 这里是调用上面定义的emit函数
}
</script>

<!-- 父组件 -->
<ChildComponent @update="handleUpdate" />

emit与props配合,实现了Vue组件间的双向通信机制。


分项解释3 - @update和@input

相同点

  • 都是事件监听语法
  • 都使用 @ 符号作为简写
  • 都用于响应某个动作

不同点

@input

  • 原生DOM事件(浏览器内置)
  • 浏览器自动触发(用户输入时)
  • 主要用于表单元素
<input @input="handleInput" />
<!-- 用户输入时自动触发 -->

@update

  • 自定义组件事件
  • 需要子组件手动触发(通过 emit
  • 用于组件间通信
<!-- 子组件内部 -->
emit('update', data)

<!-- 父组件使用 -->
<ChildComponent @update="handleUpdate" />

总结

  • @input:监听浏览器原生输入事件
  • @update:监听子组件自定义事件

一个是"被动监听",一个是"主动通知"的关系!


分项解释4 - @update:modelValue

这是Vue中v-model的自定义实现语法:

  • 用于实现自定义组件的v-model
  • 是Vue 3中v-model的底层机制

传统v-model等价关系

<!-- 这两种写法是等价的 -->
<CustomInput v-model="searchText" />

<CustomInput
  :modelValue="searchText"
  @update:modelValue="newValue => searchText = newValue"
/>

完整示例

子组件

<script setup>
// 定义组件接收的属性:一个名为modelValue的prop(来自父组件v-model绑定的值)
defineProps(['modelValue'])

// 定义组件可以发射的事件:一个名为update:modelValue的自定义事件
defineEmits(['update:modelValue'])

// 处理输入框输入事件的函数
function updateValue(event) {
  // 发射update:modelValue事件,将输入框的新值传递给父组件
  // event.target.value是输入框当前的值
  emit('update:modelValue', event.target.value)
}
</script>

<template>
  <!-- 
    输入框组件:
    :value="modelValue" - 将输入框的值绑定到从父组件传来的modelValue
    @input="updateValue" - 当输入框有输入时,触发updateValue函数
  -->
  <input 
    :value="modelValue"
    @input="updateValue"
  />
</template>

父组件

<CustomInput v-model="text" />
<!-- 等价于 -->
<CustomInput 
  :modelValue="text"
  @update:modelValue="newValue => text = newValue"
/>

数据流向说明:

父组件 v-model="text"
    → 子组件 :modelValue="text" (props传入)
    → 用户输入 → @input触发 → emit发射事件
    → 父组件 @update:modelValue接收 → 更新text

总结

@update:modelValue 是v-model的事件监听部分,用于接收子组件的数据更新通知!



Vue3 最新的父子通信(双向绑定)方式

Vue 3.4+ 官方文档 推荐使用 defineModel,大大简化了双向绑定的实现。

新旧对比

旧方式(复杂)

<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])

function updateValue(event) {
  emit('update:modelValue', event.target.value)
}
</script>

<template>
  <input 
    :value="modelValue"
    @input="updateValue"
  />
</template>

新方式(简洁)

<script setup>
const modelValue = defineModel()
</script>

<template>
  <input v-model="modelValue" />
</template>

defineModel 的优势

  1. 一行代码搞定:替代了 defineProps + defineEmits + 更新函数
  2. 直接使用 v-model:在模板中可以直接用 v-model 绑定
  3. 类型安全:更好的 TypeScript 支持
  4. 更直观:逻辑更清晰易懂

使用方法

基本用法

<script setup>
const value = defineModel()
</script>

<template>
  <input v-model="value" />
</template>

带默认值和类型

<script setup>
const count = defineModel({ default: 0, type: Number })
</script>

结论

Vue 3.4+ 强烈推荐使用 defineModel,不再需要手动拆解 props 和 emit,代码更加简洁优雅!

这是 Vue 双向绑定演进的重要改进!

posted @ 2025-11-17 11:18  岑素月  阅读(14)  评论(0)    收藏  举报