Vue 3 选项式 API 完全指南
本文档从零开始讲解 Vue 3 的选项式 API:什么是选项式 API、和组合式 API 有何不同、如何用 data、computed、methods、watch、props、生命周期 等选项组织组件,配有大量示例,适合新手系统学习。各选项的详细说明见《Vue3实例选项.md》。
一、什么是选项式 API?
1.1 概念
选项式 API 是指:用一个配置对象来定义组件,对象里按功能类型分成不同的“选项”,例如 data 放数据、methods 放方法、mounted 放挂载后的逻辑。
你在 .vue 里 export default { data(), methods: {}, mounted() {} },就是在用选项式 API。
export default {
data() {
return { count: 0 }
},
methods: {
add() {
this.count++
}
},
mounted() {
console.log('挂载完成', this.count)
}
}
- this 指向当前组件实例,通过 this.count、this.add() 访问数据和方法。
- 模板里可以直接写 count、add,Vue 会从实例上取。
1.2 为什么叫“选项式”?
因为逻辑是按选项(options)分的:数据归 data,方法归 methods,生命周期归 mounted、created 等。
与之相对的是 组合式 API:用 setup 或 ,用 ref、onMounted 等函数把“同一块功能”写在一起,不按 data/methods 分块。
二、选项式 API 与组合式 API 对比
2.1 写法对比
选项式: 按“类型”分块,用 this。
export default {
data() {
return { count: 0 }
},
computed: {
double() {
return this.count * 2
}
},
methods: {
add() {
this.count++
}
},
mounted() {
console.log(this.count)
}
}
组合式(): 按“功能”组织,用变量和函数。
import { ref, computed, onMounted } from 'vue'
const count = ref(0)
const double = computed(() => count.value * 2)
function add() {
count.value++
}
onMounted(() => {
console.log(count.value)
})
2.2 何时用选项式?
- 你或团队习惯选项式、老项目已是选项式,可以继续用。
- 喜欢“数据一块、方法一块”的分块清晰感。
- Vue 3 同时支持选项式和组合式,同一项目里可以混用(不推荐过度混用)。
2.3 何时用组合式?
- 逻辑复用方便(组合式函数 useXxx),按功能组织代码。
- 官方文档和生态更偏向组合式 + 。
- 需要 TypeScript 时,组合式类型推断更自然。
本文档只讲选项式的用法;组合式见《Vue3组合式API.md》。
三、data —— 组件的数据
3.1 必须写成函数
data 必须是函数,返回一个对象。
对象里的属性会变成响应式的,并挂到 this 上。
export default {
data() {
return {
count: 0,
name: '',
list: []
}
}
}
模板里:{{ count }}、{{ name }}。
在 methods、mounted 里:this.count、this.list.push(1)。
3.2 为什么不能直接写对象?
若写 data: { count: 0 },所有用到这个组件的实例会共享同一份 data。
写成函数后,每个实例调用一次 data(),得到各自的对象,互不影响。
3.3 示例:计数器
export default {
data() {
return {
count: 0
}
},
methods: {
add() {
this.count++
}
}
}
<template>
<p>{{ count }}</p>
<button @click="add">+1</button>
</template>
四、computed —— 计算属性
4.1 作用
computed 里定义依赖其它数据算出来的值;会缓存,依赖不变就不会重新算。
在模板和 this 上当属性用,不用加括号。
4.2 只读(函数写法)
export default {
data() {
return { count: 0 }
},
computed: {
double() {
return this.count * 2
}
}
}
模板:{{ double }}。
4.3 可写(get/set)
computed: {
fullName: {
get() {
return this.firstName + ' ' + this.lastName
},
set(val) {
const [a, b] = val.split(' ')
this.firstName = a
this.lastName = b
}
}
}
详见《Vue3计算属性.md》。
五、methods —— 方法
5.1 作用
methods 里定义方法,会挂到 this 上;可在模板里 @click=”add”、在其它方法里 this.add()。
5.2 基本写法
export default {
data() {
return { count: 0 }
},
methods: {
add() {
this.count++
},
addN(n) {
this.count += n
}
}
}
<button @click="add">+1</button>
<button @click="addN(5)">+5</button>
5.3 访问 data、computed、其它 methods
在 methods 里用 this.xxx 访问 data、computed、props 或其它 methods。
methods: {
submit() {
if (!this.valid) return
console.log(this.form)
this.reset()
},
reset() {
this.form = { name: '', age: 0 }
}
}
六、watch —— 侦听器
6.1 作用
watch 用来监听某个数据的变化,变化时执行你写的函数(如请求接口、存本地)。
6.2 简单写法
export default {
data() {
return { keyword: '' }
},
watch: {
keyword(newVal, oldVal) {
console.log(newVal, oldVal)
}
}
}
6.3 带选项(deep、immediate)
watch: {
form: {
handler(newVal) {
console.log('form 变了', newVal)
},
deep: true,
immediate: true
}
}
6.4 监听对象属性
watch: {
'form.name'(newVal) {
console.log(newVal)
}
}
详见《Vue3监听属性.md》。
七、props —— 父传子的数据
7.1 声明与使用
props 声明组件从父组件接收哪些属性;父用 :xxx=”值” 传,子用 this.xxx 或模板里 xxx。
props 是只读的,不要在本组件里改。
export default {
props: ['title', 'count'],
mounted() {
console.log(this.title, this.count)
}
}
或带类型与默认值:
props: {
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
}
详见《Vue3组件.md》。
八、emits —— 声明自定义事件
8.1 作用
emits 声明组件会向父组件触发哪些事件;触发用 this.$emit(‘事件名’, 参数)。
推荐写上,便于文档和校验。
export default {
emits: ['update', 'close'],
methods: {
save() {
this.$emit('update', this.form)
},
close() {
this.$emit('close')
}
}
}
父组件:。
九、生命周期钩子
在选项对象里直接写钩子函数,Vue 在对应阶段会调用。
| 选项 | 执行时机 |
|---|---|
| beforeCreate | 实例创建后、data 等未初始化 |
| created | data、methods 已有,DOM 未挂载 |
| beforeMount | 即将挂载到 DOM 前 |
| mounted | 已挂载,可操作 $el、$refs |
| beforeUpdate | 数据变化,DOM 即将更新前 |
| updated | DOM 更新完成后 |
| beforeUnmount | 即将销毁前 |
| unmounted | 已销毁,做清理 |
export default {
data() {
return { count: 0 }
},
created() {
console.log('created', this.count)
},
mounted() {
console.log('mounted', this.$el)
window.addEventListener('resize', this.onResize)
},
unmounted() {
window.removeEventListener('resize', this.onResize)
},
methods: {
onResize() {}
}
}
详见《Vue3中生命周期钩子.md》。
十、components、directives、mixins
10.1 components —— 局部组件
import Child from './Child.vue'
export default {
components: {
Child
}
}
模板里:。
10.2 directives —— 局部指令
export default {
directives: {
focus: {
mounted(el) {
el.focus()
}
}
}
}
模板里:。
10.3 mixins —— 混入
import { timeMixin } from './mixins/timeMixin'
export default {
mixins: [timeMixin]
}
混入的 data、methods、mounted 等会按规则合并进当前组件。详见《Vue3混入.md》。
十一、provide / inject
11.1 provide
在父(或祖先)组件里提供数据或方法:
export default {
data() {
return { theme: 'dark' }
},
provide() {
return {
theme: this.theme
}
}
}
11.2 inject
在子孙组件里注入:
export default {
inject: ['theme']
}
模板和 this 里用 this.theme。
十二、name、inheritAttrs
12.1 name
name 指定组件名,用于开发工具、keep-alive 的 include/exclude 等。
export default {
name: 'UserCard'
}
12.2 inheritAttrs
inheritAttrs: false 可关闭“未在 props 声明的属性自动加到根元素”的行为,改由自己在模板里 v-bind=”$attrs” 决定绑到哪。
export default {
inheritAttrs: false
}
十三、完整示例:选项式组件
// UserCard.vue
export default {
name: 'UserCard',
components: {
UserAvatar: () => import('./UserAvatar.vue')
},
props: {
user: {
type: Object,
required: true
}
},
data() {
return {
loading: false,
expanded: false
}
},
computed: {
displayName() {
return this.user?.name ?? '匿名'
}
},
watch: {
'user.id'() {
this.loadDetail()
}
},
emits: ['edit'],
created() {
this.loadDetail()
},
mounted() {
console.log('挂载完成')
},
methods: {
async loadDetail() {
this.loading = true
try {
// const res = await fetch(...)
} finally {
this.loading = false
}
},
toggle() {
this.expanded = !this.expanded
},
onEdit() {
this.$emit('edit', this.user)
}
}
}
<template>
<div class="user-card">
<UserAvatar :user="user" />
<p>{{ displayName }}</p>
<button @click="toggle">展开/收起</button>
<button @click="onEdit">编辑</button>
</div>
</template>
十四、选项式 API 速查表
| 选项 | 作用 |
|---|---|
| data | 响应式数据(必须为函数,返回对象) |
| computed | 计算属性 |
| methods | 方法 |
| watch | 侦听器 |
| props | 声明接收的 props |
| emits | 声明自定义事件 |
| beforeCreate~unmounted | 生命周期钩子 |
| components | 局部注册组件 |
| directives | 局部注册指令 |
| mixins | 混入 |
| provide / inject | 依赖注入 |
| name | 组件名 |
| inheritAttrs | 是否继承根节点未声明属性 |
十五、学习建议
- 先练熟 data、methods、computed、mounted,能写一个完整的选项式页面。
- 再按需加 props、emits、watch、components;需要跨层级再用 provide/inject。
- 理解 this 指向组件实例,在 methods、生命周期里用 this.xxx 访问数据和方法。
- 各选项的细节、边界情况可查《Vue3实例选项.md》;组合式写法见《Vue3组合式API.md》。
把本文档里的 UserCard 示例在项目里敲一遍、改一改,会掌握得更牢。祝你学习顺利。