Vue 组件:单文件组件与组合式 API
Vue 3 引入的组合式 API(Composition API)配合单文件组件(SFC),极大地提升了代码的逻辑复用性和类型推导能力。本指南将详细介绍如何从零开始构建一个结构清晰、逻辑严密的 Vue 组件。
理解单文件组件结构
单文件组件(.vue 文件)将一个组件的逻辑、模板和样式封装在同一个文件中。
- 新建一个后缀为
.vue的文件,例如UserProfile.vue。 - 编写基础的文件结构,包含三个顶层标签:
<template>
<!-- HTML 模板区域 -->
</template>
<script setup>
<!-- JavaScript 逻辑区域 -->
</script>
<style scoped>
/* CSS 样式区域 */
</style>
<script setup> 是一个编译时宏,使得组合式 API 的使用更加简洁。在 style 标签上添加 scoped 属性,可以确保 CSS 样式仅作用于当前组件。
定义响应式数据
在组合式 API 中,我们需要显式地创建响应式状态。ref 用于基本类型,reactive 用于对象类型。
- 导入
ref和reactive函数。 - 声明变量
userName存储字符串,userInfo存储对象。
<script setup>
import { ref, reactive } from 'vue';
// 使用 ref 定义基本类型响应式数据
const userName = ref('张三');
// 使用 reactive 定义对象类型响应式数据
const userInfo = reactive({
age: 25,
email: 'zhangsan@example.com'
});
</script>
在 <script> 中修改 ref 的值需要通过 .value 属性,而在 <template> 中会自动解包,无需使用 .value。
实现计算属性
计算属性用于基于响应式数据衍生出新的状态,具有缓存特性。
- 导入
computed函数。 - 创建一个计算属性
description,自动拼接用户信息。
<script setup>
import { ref, reactive, computed } from 'vue';
// ... 前面的响应式数据定义 ...
// 定义计算属性
const description = computed(() => {
return `${userName.value} 今年 ${userInfo.age} 岁`;
});
</script>
若要计算带有折扣的价格,可以使用数学公式表达逻辑。假设原价为 $P$,折扣率为 $d$,最终价格为 $F = P \times (1 - d)$。
const price = ref(100);
const discount = ref(0.1); // 10% 折扣
const finalPrice = computed(() => {
return price.value * (1 - discount.value);
});
编写方法与事件处理
组件内的交互逻辑通过方法实现。
- 定义
updateAge函数来修改年龄。 - 定义
resetInfo函数来重置数据。
<script setup>
// ... 导入和定义 ...
const updateAge = () => {
userInfo.age += 1;
};
const resetInfo = () => {
userName.value = '匿名';
userInfo.age = 0;
};
</script>
在模板中,使用 @ 符号(v-on 的简写)绑定事件:
<template>
<div>
<p>姓名: {{ userName }}</p>
<p>简介: {{ description }}</p>
<button @click="updateAge">增加年龄</button>
<button @click="resetInfo">重置信息</button>
</div>
</template>
组件通信:Props 与 Emits
组件间通信通过 Props 接收数据,通过 Emits 触发事件。
- 定义
props,接收父组件传递的初始数据。 - 定义
emits,声明可触发的事件列表。
<script setup>
// 使用 defineProps 定义接收的属性
const props = defineProps({
initialTitle: {
type: String,
default: '默认标题'
}
});
// 使用 defineEmits 定义可触发的事件
const emit = defineEmits(['submit-form']);
const handleSubmit = () => {
// 触发事件,并传递数据给父组件
emit('submit-form', { user: userName.value, age: userInfo.age });
};
</script>
在模板中使用 props:
<template>
<h1>{{ initialTitle }}</h1>
<button @click="handleSubmit">提交表单</button>
</template>
生命周期钩子
组合式 API 提供了 onMounted、onUpdated 等生命周期钩子函数。
- 导入所需的生命周期函数。
- 调用钩子函数并在回调中执行逻辑。
<script setup>
import { onMounted, onUnmounted } from 'vue';
onMounted(() => {
console.log('组件已挂载到 DOM');
});
onUnmounted(() => {
console.log('组件即将卸载');
});
</script>
以下是组件生命周期的执行流程示意图,清晰展示了从创建到销毁的各个阶段:
响应式 API 对比
为了更好地选择合适的 API,下表列出了 ref 和 reactive 的主要区别:
| 特性 | ref | reactive |
|---|---|---|
| 适用数据 | 基本类型、对象、数组 | 对象、数组 |
| 访问/修改方式 | 脚本中需 .value,模板自动解包 |
直接访问属性 |
| 解构响应性 | 失去响应性(需 toRefs) |
失去响应性(需 toRefs) |
| 重新赋值 | 支持 value = xxx 替换整个对象 |
不支持直接替换,需修改属性 |
样式处理
在 <style> 标签中,可以使用 CSS 变量或 Scoped 样式来管理组件外观。
- 编写 scoped 样式,确保样式隔离。
- 使用
v-bind将 CSS 变量与 JavaScript 动态绑定。
<script setup>
const themeColor = ref('blue');
</script>
<template>
<div class="box">彩色盒子</div>
<button @click="themeColor = 'red'">变红</button>
</template>
<style scoped>
.box {
/* 使用 v-bind 绑定 JS 变量 */
background-color: v-bind('themeColor');
padding: 20px;
color: white;
}
</style>
通过以上步骤,你已经掌握了使用 Vue 3 单文件组件和组合式 API 构建完整功能组件的核心流程。

暂无评论,快来抢沙发吧!