选项式 API 是 Vue 最经典的组件编写方式。一个 .vue 文件就是一个组件,你通过在特定的 选项(Options) 中填充代码来定义组件的各个部分:数据放在 data 里,方法放在 methods 里,计算属性放在 computed 里,监听器放在 watch 里,接收的外部参数放在 props 里,触发的事件声明在 emits 里。这种“按功能分块”的结构,让初学者很容易理解“一个组件由哪些要素构成”。
<script>
export default {
// 组件名(可选)
name: 'UserProfile',
// 接收父组件传入的数据
props: {
userId: { type: String, required: true }
},
// 声明触发的自定义事件
emits: ['update'],
// 组件内部响应式数据
data() {
return {
user: null,
loading: false
}
},
// 计算属性(带缓存)
computed: {
displayName() {
return this.user ? this.user.name : '未知用户'
}
},
// 侦听器
watch: {
userId: {
immediate: true,
handler(newId) {
this.fetchUser(newId)
}
}
},
// 方法
methods: {
async fetchUser(id) {
this.loading = true
try {
// 发起请求...
this.user = await api.getUser(id)
} finally {
this.loading = false
}
},
updateName(newName) {
this.user.name = newName
this.$emit('update', this.user)
}
},
// 生命周期钩子
created() {
console.log('组件实例刚创建好,可以访问 data 和 methods 了')
},
mounted() {
console.log('组件已经挂载到 DOM 上')
}
}
</script>
这就是选项式 API 的典型形态:每个“是什么”归在一个选项里。它强制了一种约定,让同一类东西聚在一起,读代码时可以快速定位到“数据定义区”、“方法区”或“生命周期区”。
核心配置项速览
1. data
- 必须是一个返回对象的函数,因为组件可能被复用,每个实例需要独立的数据副本。
- 返回的对象会被 Vue 转换为响应式对象,在模板中可以直接通过
{{ }}访问,在脚本中用this访问。 - 注意:
data中不要以_或$开头命名属性,防止与 Vue 内部属性冲突。
2. methods
- 定义组件的方法,用于处理事件、操作数据、触发逻辑。
- 方法中的
this自动绑定到组件实例,因此可以直接通过this.xxx访问data、computed或其他方法。 - 不适合写箭头函数,否则
this不会指向组件实例。
3. computed
- 计算属性,基于响应式依赖动态计算出一个值,带缓存:只有依赖变化时才会重新计算。
- 默认只有 getter,但可以设置
get和set实现可写计算属性。 - 适合用于格式化展示、过滤列表、状态派生等场景,例如根据
price和discount算出实际售价。
4. watch
- 监听
data或computed的变化,执行副作用(如请求数据、操作 DOM、记录日志)。 - 支持简写为方法,也可以写成对象,配置
deep(深度监听)、immediate(立即执行)、handler。 - 与
computed的区别:computed用于同步计算出一个新值,watch用于当数据变化时需要做点什么(通常是异步或复杂操作)。
5. props
- 从父组件接收数据,类型可以是数组(只声明名称)或对象(带类型校验、默认值、必填标记等)。
- 遵循单向数据流:子组件不应直接修改 props,若要修改应通过
emits通知父组件处理。 - 校验失败会在控制台发出警告(仅开发环境),不影响运行,但应重视以保障组件的健壮性。
6. emits
- 声明组件可以触发的自定义事件,既用于文档化,也用于 Vue 运行时校验(可选)。
- 在组件内部通过
this.$emit('事件名', 参数)触发,父组件用@事件名="handler"监听。 - 结合
v-model时,若需要自定义双向绑定,会用到特定的update:modelValue事件。
生命周期选项与执行时机
每个 Vue 组件实例从创建到销毁会经历一系列步骤,选项式 API 通过特定的生命周期钩子函数让你在关键节点注入代码。
| 钩子(Vue 3) | 在何时被调用 | 常用场景 |
|------------------|--------------------------------------------------|----------------------------------|
| beforeCreate | 实例刚初始化,data/watch/methods 等还未配置 | 极少使用(几乎用不到) |
| created | 实例创建完成,已完成数据观测和计算属性 setup | 请求初始数据,但此时无法操作 DOM |
| beforeMount | 模板编译完成,准备挂载到 DOM 前 | 同样少见 |
| mounted | 组件挂载到页面后,DOM 已可用 | 操作 DOM、初始化第三方库、获取焦点 |
| beforeUpdate | 数据变化,更新 DOM 之前 | 在更新前手动获取旧的 DOM 状态 |
| updated | 数据变化导致 DOM 更新完成后 | 避免在此修改数据,以免死循环 |
| beforeUnmount | 组件卸载前调用(Vue 3) | 清理定时器、取消订阅、解绑事件 |
| unmounted | 组件卸载后调用(Vue 3) | 最终清理(但大部分工作宜在 beforeUnmount 做) |
| errorCaptured | 捕获后代组件错误 | 错误边界处理 |
Vue 2 注意:销毁相关的钩子原名为
beforeDestroy和destroyed,Vue 3 更名为beforeUnmount和unmounted,语义更准确。
实际开发中最常用的三个是 created(拿数据)、mounted(摸 DOM)、beforeUnmount(清垃圾)。这个顺序表很像一个“组件的生平档案”,你只需要在对应的时期写代码。
适用场景与代码组织特点
适用场景
- 中小型组件或页面:逻辑比较直白,数据、计算、方法分类自然,选项式 API 写起来顺手。
- 团队技术栈偏传统:很多从 jQuery 或后端 MVC 过渡过来的开发者,对“按类型分块”的代码组织很熟悉,容易上手。
- 维护 Vue 2 老项目:Vue 3 完全兼容选项式 API,老代码不动筋骨也能继续跑。
- 快速原型:用选项式不用思考组合逻辑,直接往对应选项里填代码即可,开发速度很快。
代码组织特点
选项式 API 最大的特点是 “割裂的同理心”——同一段业务逻辑(如获取用户数据、处理搜索、分页逻辑)会被拆分到不同的选项中:data 里放变量,methods 里放函数,watch 里放副作用触发,mounted 里发起首次请求。当组件逻辑变复杂时,阅读代码需要反复在几个选项之间横跳,这就是常见的 “碎片化逻辑” 问题。
以一个简单的搜索框为例:搜索关键词存在 data,输入处理方法在 methods,关键词变化后发起请求的逻辑在 watch,加载状态切换在请求方法里手动控制——这些为完成同一件事的代码被撒在了三个选项里。当组件有多个这样的功能模块(搜索、分页、筛选、弹窗)混在一起时,一个选项内就会塞满不相关的代码,维护效率下降。
这正是组合式 API(Composition API)要解决的核心痛点:把同一段业务逻辑的代码通过 setup 函数集结在一起,不再受选项“切割”。但这并不意味着选项式 API 就被淘汰了——对于简单组件,选项式依然是清晰、直接、高效的选择。两种 API 在同一个项目中甚至可以共存,Vue 的渐进式哲学依然体现在此处:需要组织复杂逻辑时再用组合式,简单场景用选项式就够。