Vue3 组件化开发核心:组件定义、Props 与 Emits 父子传值

1. Vue3 组件定义与 Props 父子传值

1.1 Props:父组件向子组件传递数据

Props 是父组件向子组件传递数据的单向数据流。

父组件传递数据
vue 复制代码
<!-- ParentComponent.vue -->
<template>
  <div>
    <h2>父组件</h2>
    <!-- 使用 v-bind 或 : 传递数据 -->
    <ChildComponent :message="parentMessage" />
  </div>
</template>

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

const parentMessage = ref('这是来自父组件的问候!')
</script>
Props 的类型与验证

可以为 Props 指定类型并进行验证,提高代码健壮性。

javascript 复制代码
const props = defineProps({
  // 基础类型检查
  title: String,
  
  // 多个可能的类型
  value: [String, Number],
  
  // 必填项
  userId: {
    type: Number,
    required: true
  },
  
  // 带默认值
  size: {
    type: String,
    default: 'medium'
  },
  
  // 自定义验证函数
  score: {
    type: Number,
    validator: (value) => {
      return value >= 0 && value <= 100
    }
  }
})

1.2 使用 Props 的注意事项

  1. 单向数据流:Props 是只读的,子组件不应直接修改。
  2. 动态与静态传递
    • 静态:<Child title="静态标题" />
    • 动态:<Child :title="dynamicTitle" />

2. 掌握 defineEmits 子向父传值

2.1 使用 defineEmits 定义自定义事件

子组件通过触发事件向父组件通信。

vue 复制代码
<!-- ChildComponent.vue -->
<template>
  <div>
    <h3>子组件</h3>
    <button @click="sendMessage">向父组件发送消息</button>
  </div>
</template>

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

// 定义可触发的事件
const emit = defineEmits(['message-sent', 'update:count'])

const sendMessage = () => {
  // 触发事件并传递数据
  emit('message-sent', '你好,父组件!')
  
  // 触发更新事件(常用于 v-model 双向绑定)
  emit('update:count', 10)
}
</script>

2.2 父组件监听子组件事件

vue 复制代码
<!-- ParentComponent.vue -->
<template>
  <div>
    <h2>父组件</h2>
    <p>收到子组件消息:{{ receivedMessage }}</p>
    <p>当前计数:{{ count }}</p>
    
    <!-- 监听子组件事件 -->
    <ChildComponent 
      @message-sent="handleMessage" 
      @update:count="count = $event"
    />
  </div>
</template>

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

const receivedMessage = ref('')
const count = ref(0)

const handleMessage = (msg) => {
  receivedMessage.value = msg
  console.log('收到子组件消息:', msg)
}
</script>

2.3 事件验证与类型提示

可以为事件添加验证和类型提示(TypeScript)。

typescript 复制代码
// 类型提示
const emit = defineEmits<{
  (e: 'message-sent', message: string): void
  (e: 'update:count', value: number): void
}>()

// 带验证的事件定义
const emit = defineEmits({
  'message-sent': (payload: string) => {
    // 返回 true 表示验证通过
    return payload.length > 0
  }
})

3. 学习组件生命周期(onMounted 等)

3.1 Vue3 生命周期钩子

在组合式 API 中,生命周期钩子以 onXxx 函数形式导入使用。

vue 复制代码
<script setup>
import { onMounted, onUpdated, onUnmounted, onBeforeMount } from 'vue'

// 组件挂载后执行
onMounted(() => {
  console.log('组件已挂载到 DOM')
  // 可以在这里进行 DOM 操作、发起网络请求等
})

// 组件更新后执行
onUpdated(() => {
  console.log('组件已更新')
})

// 组件卸载前执行
onUnmounted(() => {
  console.log('组件即将卸载')
  // 清理定时器、取消事件监听等
})

// 组件挂载前执行
onBeforeMount(() => {
  console.log('组件即将挂载')
})
</script>

3.2 完整生命周期流程图





开始
setup
onBeforeMount
onMounted
数据更新?
onBeforeUpdate
onUpdated
组件卸载?
onBeforeUnmount
onUnmounted
结束

3.3 常见使用场景

生命周期钩子 使用场景
onMounted DOM 操作、数据初始化、事件监听、API 请求
onUpdated DOM 更新后的操作、依赖更新的计算
onUnmounted 清理定时器、取消事件监听、释放资源
onBeforeMount 服务器端渲染、最后时刻的状态修改

4. 练习简单组件拆分与复用

4.1 组件拆分原则

  1. 单一职责:每个组件只负责一个特定功能
  2. 高内聚低耦合:组件内部紧密相关,组件之间依赖明确
  3. 可复用性:设计通用的、可配置的组件
  4. 清晰的接口:Props 和 Emits 定义明确

4.2 实战:按钮组件

vue 复制代码
<!-- ReusableButton.vue -->
<template>
  <button 
    :class="['btn', `btn-${type}`, { 'btn-disabled': disabled }]"
    :disabled="disabled"
    @click="handleClick"
  >
    <slot>{{ text }}</slot>
  </button>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue'

const props = defineProps({
  type: {
    type: String,
    default: 'primary',
    validator: (value) => ['primary', 'secondary', 'danger'].includes(value)
  },
  text: {
    type: String,
    default: '按钮'
  },
  disabled: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['click'])

const handleClick = () => {
  if (!props.disabled) {
    emit('click')
  }
}
</script>

<style scoped>
.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
}

.btn-primary {
  background-color: #007bff;
  color: white;
}

.btn-secondary {
  background-color: #6c757d;
  color: white;
}

.btn-danger {
  background-color: #dc3545;
  color: white;
}

.btn-disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
</style>

4.3 使用示例

vue 复制代码
<!-- App.vue -->
<template>
  <div>
    <h1>按钮组件示例</h1>
    
    <ReusableButton 
      type="primary" 
      text="主要按钮" 
      @click="handlePrimaryClick"
    />
    
    <ReusableButton 
      type="secondary" 
      @click="handleSecondaryClick"
    >
      自定义内容
    </ReusableButton>
    
    <ReusableButton 
      type="danger" 
      text="危险按钮" 
      :disabled="true"
    />
  </div>
</template>

<script setup>
import ReusableButton from './components/ReusableButton.vue'

const handlePrimaryClick = () => {
  console.log('主要按钮被点击')
}

const handleSecondaryClick = () => {
  console.log('次要按钮被点击')
}
</script>

总结:Vue3 的组件化开发通过清晰的 Props 和 Emits 接口实现了父子组件通信,组合式 API 让逻辑组织更加灵活。掌握这些核心概念后,可以构建出可维护、可复用的前端应用。建议在实际项目中多加练习,不断优化组件设计。

相关推荐
yuanyxh1 天前
Mac 软件推荐
前端·javascript·程序员
万少1 天前
AtomCode开发微信小程序《谁去呀》 全流程
前端·javascript·后端
某人辛木1 天前
Web自动化测试
前端·python·pycharm·pytest
Kagol1 天前
Superpowers GSD gstack AgentSkills深度测评
前端·人工智能
excel1 天前
JavaScript 字符串与模板字面量:从表象到本质理解
前端
京东云开发者1 天前
当AI成为导演-如何用AI创作动漫短剧
前端
李白的天不白1 天前
使用 SmartAdmin 进行前后端开发
java·前端
乘风gg1 天前
🤡PUA AI Coding 工具 的 10 条终极语录
前端·ai编程·claude
学Linux的语莫1 天前
Vue 3 入门教程
前端·javascript·vue.js
怕浪猫1 天前
第一章、Chrome DevTools Protocol (CDP) 详解
前端·javascript·chrome