人人都会AI编程

8.1 选项式 API(Options API)

更新时间:2026-07-11

选项式 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 访问 datacomputed 或其他方法。
  • 不适合写箭头函数,否则 this 不会指向组件实例。

3. computed

  • 计算属性,基于响应式依赖动态计算出一个值,带缓存:只有依赖变化时才会重新计算。
  • 默认只有 getter,但可以设置 getset 实现可写计算属性。
  • 适合用于格式化展示、过滤列表、状态派生等场景,例如根据 pricediscount 算出实际售价。

4. watch

  • 监听 datacomputed 的变化,执行副作用(如请求数据、操作 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 注意:销毁相关的钩子原名为 beforeDestroydestroyed,Vue 3 更名为 beforeUnmountunmounted,语义更准确。

实际开发中最常用的三个是 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 的渐进式哲学依然体现在此处:需要组织复杂逻辑时再用组合式,简单场景用选项式就够