Vue3 组件化开发入门:Props 与 Emit 完全指南

在 Vue3 中,组件是构建应用的基本单元。  
组件之间的通信主要分为:

- **父 → 子**:通过 Props 传递数据
- **子 → 父**:通过 Emit 触发事件

----------

一、父向子通信:Props

基本用法

<!-- 父组件 -->
<UserCard name="Alice" age="25" />

<!-- 子组件 UserCard.vue -->
<template>
  <div>
    <h3>{{ name }}({{ age }} 岁)</h3>
  </div>
</template>

<script setup>
defineProps({
  name: String,
  age: Number
})
</script>

动态传递

<!-- 父组件 -->
<UserCard :name="username" :age="userage" />

<script setup>
const username = 'Jack'
const userage = 30
</script>

二、子向父通信:Emit

基本用法

<!-- 子组件 MyButton.vue -->
<template>
  <button @click="$emit('custom-click', '来自子组件的数据')">
    点击我
  </button>
</template>

<script setup>
defineEmits(['custom-click'])
</script>

<!-- 父组件 -->
<MyButton @custom-click="handleClick" />

<script setup>
function handleClick(data) {
  console.log('父组件收到:', data)
}
</script>

三、Props 与 Emit 结合示例

做一个简单的计数器组件,父组件传入初始值,子组件点击按钮修改并通知父组件。

Counter.vue(子组件)
<template>
  <div>
    <p>当前计数:{{ count }}</p>
    <button @click="increment">+1</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const props = defineProps({
  modelValue: Number
})
const emit = defineEmits(['update:modelValue'])

const count = ref(props.modelValue)

function increment() {
  count.value++
  emit('update:modelValue', count.value) // 通知父组件更新
}
</script>
App.vue(父组件)
<template>
  <Counter v-model="num" />
  <p>父组件同步的值:{{ num }}</p>
</template>

<script setup>
import { ref } from 'vue'
import Counter from './Counter.vue'

const num = ref(0)
</script>

四、注意事项

  • Props 是单向数据流
    • 子组件不能直接修改 Props

    • 如果需要修改,先拷贝到本地变量,或通过 Emit 通知父组件更新

  • Emit 事件命名
    • 建议用小写加中划线(如 custom-click),符合 Vue 事件命名规范

    • update:modelValue 是 v-model 的默认事件

五、实战小项目:Todo 列表组件化拆分

父组件管理任务数据,子组件负责渲染任务和触发完成事件。

TodoItem.vue
<template>
  <li>
    {{ todo.text }}
    <button @click="$emit('done', todo.id)">完成</button>
  </li>
</template>

<script setup>
defineProps({
  todo: Object
})
defineEmits(['done'])
</script>
App.vue
<template>
  <ul>
    <TodoItem
      v-for="t in todos"
      :key="t.id"
      :todo="t"
      @done="markDone"
    />
  </ul>
</template>

<script setup>
import { ref } from 'vue'
import TodoItem from './TodoItem.vue'

const todos = ref([
  { id: 1, text: '学习 Vue3', done: false },
  { id: 2, text: '写一篇文章', done: false }
])

function markDone(id) {
  todos.value = todos.value.filter(t => t.id !== id)
}
</script>

小结

  • Props → 父传子(数据单向流动)

  • Emit → 子传父(事件通知)

  • 结合 v-model 可以实现双向绑定

  • 组件拆分能让代码更可维护、更可复用

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值