Vue 3 实例选项完全指南
本文档从零开始讲解 Vue 3 的实例选项:在用选项式 API 定义组件时,export default { } 里可以写哪些选项(data、props、computed、methods、watch、生命周期、setup 等)、各自的作用和写法,配有大量示例,适合新手系统学习。
一、什么是“实例选项”?
1.1 概念
在 选项式 API 里,一个组件是通过 export default 导出一个配置对象来定义的。
这个对象里的每一个键(如 data、methods、mounted)就是一个实例选项。
Vue 会根据这些选项创建组件实例:例如根据 data 生成响应式数据,根据 methods 生成方法,在对应时机执行 mounted 等。
1.2 和 的关系
是组合式 API 的写法,没有“选项对象”,而是用 ref、onMounted 等函数。
本文讲的是选项式写法:export default { data(), methods: {}, mounted() {} } 这一套。
了解实例选项有助于阅读老项目、或选择用选项式写组件时使用。
二、data —— 组件的数据
2.1 作用
data 用来定义组件的响应式数据。
必须是函数,返回一个对象;对象里的属性会变成响应式的,并挂到组件实例 this 上。
2.2 写法
export default {
data() {
return {
count: 0,
name: '',
list: []
}
}
}
- 在模板里用 count、name、list。
- 在 methods、mounted 等里用 this.count、this.name。
2.3 为什么必须是函数?
每个组件可能有多个实例(同一组件被用多次)。
若 data 是普通对象,所有实例会共享同一份数据;写成函数后,每次创建实例都会执行一次 data(),得到各自的对象,互不干扰。
data() {
return { count: 0 }
}
三、props —— 父组件传入的数据
3.1 作用
props 声明组件从父组件接收哪些属性;父组件通过 :xxx=”值” 传入,子组件通过 this.xxx 或模板里 xxx 使用。
props 是只读的,不要在本组件里修改。
3.2 写法
数组写法(只声明名字):
export default {
props: ['title', 'count']
}
对象写法(带类型、默认值、必填):
export default {
props: {
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
}
}
在模板和 this 里用 this.title、this.count。
四、computed —— 计算属性
4.1 作用
computed 里定义依赖其它数据计算出来的值;会缓存,依赖不变就不会重新计算。
在模板里当属性用,不用加括号;在 this 上也是 this.xxx。
4.2 写法
只读(函数写法):
export default {
data() {
return { count: 0 }
},
computed: {
double() {
return this.count * 2
}
}
}
可写(get/set):
computed: {
fullName: {
get() {
return this.firstName + ' ' + this.lastName
},
set(val) {
const [first, last] = val.split(' ')
this.firstName = first
this.lastName = last
}
}
}
模板里:{{ double }}、{{ fullName }}。
五、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(10)">+10</button>
注意: 在模板里需要传参时要写 addN(10);需要事件对象时写 add($event) 或 add(无参时 Vue 会传事件对象)。
六、watch —— 侦听器
6.1 作用
watch 用来监听某个数据的变化,变化时执行你写的函数(如请求接口、存本地)。
6.2 写法
简单写法(函数):
export default {
data() {
return { keyword: '' }
},
watch: {
keyword(newVal, oldVal) {
console.log(newVal, oldVal)
}
}
}
带选项(deep、immediate):
watch: {
form: {
handler(newVal) {
console.log('form 变了', newVal)
},
deep: true,
immediate: true
}
}
监听对象某个属性(字符串路径):
watch: {
'form.name'(newVal) {
console.log(newVal)
}
}
七、emits —— 声明自定义事件
7.1 作用
emits 声明组件会向父组件触发哪些自定义事件(可选,但推荐写上,便于文档和校验)。
触发用 this.$emit(‘事件名’, 参数)。
7.2 写法
数组:
export default {
emits: ['update', 'close']
}
对象(带校验):
emits: {
submit: null,
update: (payload) => {
if (payload.id) return true
console.warn('缺少 id')
return false
}
}
在 methods 里:this.$emit(‘update’, 1)。
八、components —— 局部注册组件
8.1 作用
components 用来局部注册只在当前组件里用的子组件;注册后可在模板里当标签用。
8.2 写法
import Child from './Child.vue'
export default {
components: {
Child
}
}
模板里: 或 。
九、directives —— 局部注册指令
9.1 作用
directives 用来局部注册自定义指令,只在当前组件里可用。
9.2 写法
export default {
directives: {
focus: {
mounted(el) {
el.focus()
}
}
}
}
模板里:。
十、mixins —— 混入
10.1 作用
mixins 把多个组件共用的选项(data、methods、生命周期等)抽成混入对象,按一定规则合并进当前组件。
Vue 3 更推荐用组合式函数替代混入,详见《Vue3混入.md》。
10.2 写法
import { timeMixin } from './mixins/timeMixin'
export default {
mixins: [timeMixin],
data() {
return {}
}
}
十一、provide / inject —— 依赖注入
11.1 provide
provide 用来向子孙组件提供数据或方法,不需要层层 props。
export default {
data() {
return { theme: 'dark' }
},
provide() {
return {
theme: this.theme
}
}
}
若希望 theme 是响应式的,可 provide 一个 computed 或 this 上的 getter。
11.2 inject
inject 在子孙组件里注入祖先 provide 的值。
export default {
inject: ['theme']
}
模板和 this 里用 this.theme。
可写默认值:inject: { theme: { from: ‘theme’, default: ‘light’ } }。
十二、生命周期钩子选项
在选项对象里直接写生命周期钩子函数,Vue 会在对应阶段调用。
| 选项 | 执行时机 |
|---|---|
| beforeCreate | 实例创建后、data 等初始化前 |
| created | data、methods 等已初始化,DOM 未挂载 |
| beforeMount | 即将挂载到 DOM 前 |
| mounted | 已挂载到 DOM,可操作 $el、$refs |
| beforeUpdate | 数据变化,虚拟 DOM 即将更新前 |
| updated | DOM 更新完成后 |
| beforeUnmount | 即将销毁、从 DOM 移除前 |
| unmounted | 已销毁,做清理(解绑、清定时器) |
export default {
data() {
return { count: 0 }
},
created() {
console.log('created', this.count)
},
mounted() {
console.log('mounted', this.$el)
},
unmounted() {
console.log('unmounted,做清理')
}
}
详见《Vue3中生命周期钩子.md》。
十三、name —— 组件名
13.1 作用
name 指定组件的名字,用于开发工具显示、keep-alive 的 include/exclude、递归组件等。
13.2 写法
export default {
name: 'MyComponent'
}
十四、inheritAttrs —— 是否继承根节点属性
14.1 作用
父组件在子组件上写的、未在 props 里声明的属性,默认会自动应用到子组件根元素上。
设 inheritAttrs: false 可关闭这种自动应用,改由自己在模板里用 v-bind=”$attrs” 决定绑到哪。
14.2 写法
export default {
inheritAttrs: false
}
十五、setup —— 组合式 API 入口(选项式里)
15.1 作用
在选项式组件里也可以写 setup 函数,作为组合式 API 的入口;setup 的返回值会与 data、methods 等合并到实例上。
若同时有 setup 和 data,同名时以 setup 返回的为准。
15.2 写法
import { ref } from 'vue'
export default {
data() {
return { count: 0 }
},
setup(props, context) {
const name = ref('')
return { name }
}
}
模板和 this 上既有 count(来自 data),也有 name(来自 setup)。
更多见《Vue3中setup函数.md》。
十六、完整示例:组合多个选项
export default {
name: 'UserCard',
components: {
UserAvatar: () => import('./UserAvatar.vue')
},
props: {
user: {
type: Object,
required: true
}
},
data() {
return {
loading: false
}
},
computed: {
displayName() {
return this.user?.name ?? '匿名'
}
},
watch: {
'user.id'() {
this.loadDetail()
}
},
emits: ['edit'],
created() {
this.loadDetail()
},
methods: {
loadDetail() {
this.loading = true
// ...
this.loading = false
},
onEdit() {
this.$emit('edit', this.user)
}
}
}
十七、实例选项速查表
| 选项 | 类型 | 作用 |
|---|---|---|
| data | 函数,返回对象 | 响应式数据 |
| props | 数组或对象 | 声明接收的 props |
| computed | 对象 | 计算属性 |
| methods | 对象 | 方法 |
| watch | 对象 | 侦听器 |
| emits | 数组或对象 | 声明自定义事件 |
| components | 对象 | 局部注册组件 |
| directives | 对象 | 局部注册指令 |
| mixins | 数组 | 混入 |
| provide | 对象或函数 | 向子孙提供数据 |
| inject | 数组或对象 | 注入祖先数据 |
| beforeCreate~unmounted | 函数 | 生命周期钩子 |
| name | 字符串 | 组件名 |
| inheritAttrs | 布尔 | 是否继承根节点未声明属性 |
| setup | 函数 | 组合式 API 入口 |
十八、学习建议
- 先掌握 data、methods、computed、props、mounted,能写一个完整的选项式组件。
- 再按需用 watch、emits、components、provide/inject。
- 了解 name、inheritAttrs;需要组合式时再写 setup。
- 新项目更推荐 + 组合式 API;实例选项主要用于阅读或维护选项式代码。
把本文档里的“完整示例”在项目里改一改、跑一遍,会掌握得更牢。祝你学习顺利。