Vue3选项式API

Vue 3 选项式 API 完全指南

本文档从零开始讲解 Vue 3 的选项式 API:什么是选项式 API、和组合式 API 有何不同、如何用 datacomputedmethodswatchprops生命周期 等选项组织组件,配有大量示例,适合新手系统学习。各选项的详细说明见《Vue3实例选项.md》。


一、什么是选项式 API?

1.1 概念

选项式 API 是指:用一个配置对象来定义组件,对象里按功能类型分成不同的“选项”,例如 data 放数据、methods 放方法、mounted 放挂载后的逻辑。
你在 .vueexport default { data(), methods: {}, mounted() {} },就是在用选项式 API。

export default {
  data() {
    return { count: 0 }
  },
  methods: {
    add() {
      this.count++
    }
  },
  mounted() {
    console.log('挂载完成', this.count)
  }
}
  • this 指向当前组件实例,通过 this.countthis.add() 访问数据和方法。
  • 模板里可以直接写 countadd,Vue 会从实例上取。

1.2 为什么叫“选项式”?

因为逻辑是按选项(options)分的:数据归 data,方法归 methods,生命周期归 mountedcreated 等。
与之相对的是 组合式 API:用 setup,用 refonMounted函数把“同一块功能”写在一起,不按 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 }}
methodsmounted 里:this.countthis.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 访问 datacomputedprops 或其它 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]
}

混入的 datamethodsmounted 等会按规则合并进当前组件。详见《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 声明自定义事件
beforeCreateunmounted 生命周期钩子
components 局部注册组件
directives 局部注册指令
mixins 混入
provide / inject 依赖注入
name 组件名
inheritAttrs 是否继承根节点未声明属性

十五、学习建议

  1. 先练熟 datamethodscomputedmounted,能写一个完整的选项式页面。
  2. 再按需加 propsemitswatchcomponents;需要跨层级再用 provide/inject
  3. 理解 this 指向组件实例,在 methods、生命周期里用 this.xxx 访问数据和方法。
  4. 各选项的细节、边界情况可查《Vue3实例选项.md》;组合式写法见《Vue3组合式API.md》。

把本文档里的 UserCard 示例在项目里敲一遍、改一改,会掌握得更牢。祝你学习顺利。

发表评论