文章目录
- [Vue3 概述](#Vue3 概述)
- create-vue搭建Vue3项目
- 项目目录和关键文件
- [组合式API - setup选项](#组合式API - setup选项)
- [组合式API - reactive和ref函数](#组合式API - reactive和ref函数)
- [组合式API - computed](#组合式API - computed)
- [组合式API - watch](#组合式API - watch)
- [组合式API - 生命周期钩子](#组合式API - 生命周期钩子)
- [组合式API - 父子通信](#组合式API - 父子通信)
- [组合式API - 模版引用](#组合式API - 模版引用)
- [组合式API - provide和inject](#组合式API - provide和inject)
- defineOptions
- defineModel
Vue3 概述
Vue3的优势

Vue2 选项式API 和 Vue3 组合式API

Vue 2(Options API)
js
<script>
export default {
data () {
return {
count: 0
}
},
methods: {
addCount () {
this.count++
}
}
}
</script>
Vue 3(Composition API)
js
<script setup>
import { ref } from 'vue'
const count = ref(0)
const addCount = () => count.value++
</script>
代码更加精简,分散式维护转为集中式维护,更易封装复用
create-vue搭建Vue3项目
create-vue是Vue官方新的脚手架工具,底层切换到了 vite(下一代构建工具),为开发提供极速响应
使用create-vue创建项目
- 前提环境条件:已安装 16.0 或更高版本的 Node.js
- 创建一个Vue应用
bash
npm init vue@latest
项目目录和关键文件

文件说明:
- vite.config.js - 项目的配置文件 基于vite的配置
- package.json - 项目包文件 核心依赖项变成了 Vue3.x 和 vite
- main.js - 入口文件 createApp函数创建应用实例
- app.vue - 根组件 SFC单文件组件 script - template - style
变化一:脚本script和模板template顺序调整
变化二:模板template不再要求唯一根元素
变化三:脚本script添加setup标识支持组合式API - index.html - 单页入口 提供id为app的挂载点
组合式API - setup选项
setup() 是 Vue 3 引入的组合式 API 的入口函数,用于替代 Options API 中的 data、methods、computed 等逻辑组织方式。它在组件实例创建前执行(早于 beforeCreate),此时 this 还未指向组件实例(值为 undefined)。

普通 <script> 写法(需手动 return)
html
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => {
count.value++
}
onMounted(() => {
console.log('Component mounted')
})
// 必须显式返回才能在模板中使用
return {
count,
increment
}
}
}
</script>
<script setup> 语法糖(推荐)
- 自动暴露内部变量、函数给模板。
- 编译时转换为标准组合式 API。
- 不需要 return。
html
<script setup>
import { ref, onMounted } from 'vue'
const count = ref(0)
const increment = () => {
count.value++
}
onMounted(() => {
console.log('Component mounted')
})
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
组合式API - reactive和ref函数
reactive
用于创建响应式的对象(不能用于基本类型)。
基于 Proxy 实现,对对象属性进行深度代理。
html
<script setup>
import { reactive } from 'vue'
const state = reactive({
name: 'Alice',
age: 25,
address: {
city: 'Beijing'
}
})
// 修改
state.age = 26
state.address.city = 'Shanghai' // 响应式
</script>
不能直接替换整个对象(会丢失响应性):
js
// 错误 ❌
state = reactive({ ... }) // 失去响应性
// 正确 ✅
Object.assign(state, { name: 'Bob', age: 30 })
ref
- 于创建任何类型的响应式数据(包括基本类型、对象、数组)。
- 内部通过 { value: xxx } 包装,并用 reactive 实现。
- 在 JS 中访问和修改需加 .value;在模板中自动解包。
html
<script setup>
import { ref } from 'vue'
const count = ref(0)
const user = ref({ name: 'Tom' })
// JS 中
count.value++
user.value.name = 'Jerry'
</script>
// 模板中(无需 .value)
<template>{{ count }} {{ user.name }}</template>
对比
| 特性 | reactive |
ref |
|---|---|---|
| 支持类型 | 仅对象/数组 | 所有类型 |
| 访问方式 | 直接属性访问 | .value |
| 模板使用 | 直接 | 自动解包(无需 .value) |
| 替换整个值 | 不安全 | 安全(count.value = 100) |
| 推荐场景 | 复杂对象结构 | 通用,尤其基本类型 |
✅ 建议:日常开发优先使用 ref,语义统一、不易出错。
组合式API - computed
计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法。
基于响应式依赖计算派生值,具有缓存性(依赖不变则不重新计算)。
只读计算属性
js
import { ref, computed } from 'vue'
const price = ref(100)
const tax = ref(0.1)
const totalPrice = computed(() => {
return price.value * (1 + tax.value)
})
可写计算属性(带 setter)
js
const fullName = computed({
get() {
return `${firstName.value} ${lastName.value}`
},
set(newValue) {
const [first, last] = newValue.split(' ')
firstName.value = first
lastName.value = last
}
})
组合式API - watch
侦听一个或者多个数据的变化,数据变化时执行回调函数
监听单个响应式数据
js
import { ref, watch } from 'vue'
const count = ref(0)
watch(count, (newVal, oldVal) => {
console.log(`count changed from ${oldVal} to ${newVal}`)
})
监听多个数据
js
watch([count, name], ([newCount, newName], [oldCount, oldName]) => {
console.log('Multiple values changed')
})
监听对象属性(避免 deep)
js
const user = reactive({ name: 'Alice', age: 25 })
// 只监听 age 变化,不开启 deep
watch(
() => user.age,
(newAge, oldAge) => {
console.log(`Age changed: ${oldAge} → ${newAge}`)
}
)
选项配置
js
watch(someRef, callback, {
immediate: true, // 立即执行一次
deep: true // 深度监听(适用于对象/数组)
})
注意:第一个参数传 ref 对象本身(如 count),不要写 count.value
组合式API - 生命周期钩子
组合式 API 中需显式导入生命周期函数:
| Options API | Composition API |
|---|---|
| beforeCreate | ---(直接写在 setup 开头) |
| created | --- |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
js
import { onMounted, onUnmounted } from 'vue'
onMounted(() => {
console.log('组件已挂载')
})
onUnmounted(() => {
console.log('组件即将销毁')
})
同一生命周期可注册多个回调,按顺序执行。
组合式API - 父子通信
父 → 子:Props
html
<!-- Parent.vue -->
<Child :title="pageTitle" :user-id="123" />
<!-- Child.vue -->
<script setup>
const props = defineProps({
title: String,
userId: {
type: Number,
required: true
}
})
</script>
子 → 父:Emit
html
<!-- Child.vue -->
<script setup>
const emit = defineEmits(['update-user', 'close'])
const save = () => {
emit('update-user', { id: 1, name: 'New Name' })
}
</script>
<!-- Parent.vue -->
<Child @update-user="handleUpdate" @close="onClose" />
组合式API - 模版引用
模版引用通过ref标识获取真实的dom对象或者组件实例对象
js
this.$refs.form.validate()
获取 DOM 元素
html
<script setup>
import { ref, onMounted } from 'vue'
// 1. 调用ref函数生成一个ref对象
const inputRef = ref(null)
onMounted(() => {
inputRef.value.focus() // 聚焦输入框
})
</script>
<template>
<!-- 2. 通过ref标识绑定ref对象到标签 -->
<input ref="inputRef" />
</template>
获取子组件实例
默认情况下在
html
<!-- Child.vue -->
<script setup>
const internalMethod = () => {
console.log('Called from parent')
}
// 默认不暴露任何内容
defineExpose({
internalMethod
})
</script>
父组件调用:
js
// 1. 调用ref函数生成一个ref对象
const childRef = ref(null)
onMounted(() => {
childRef.value.internalMethod()
})
<template>
<!-- 2. 通过ref标识绑定ref对象到标签 -->
<input ref="childRef" />
</template>
组合式API - provide和inject
顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
祖先组件提供数据
js
// GrandParent.vue
import { provide, ref } from 'vue'
const theme = ref('dark')
const updateTheme = (newTheme) => {
theme.value = newTheme
}
provide('theme', theme)
provide('updateTheme', updateTheme)
后代组件注入
js
// DeepChild.vue
import { inject } from 'vue'
const theme = inject('theme')
const updateTheme = inject('updateTheme')
// 响应式保持:传递的是 ref 对象,不是 .value
defineOptions
解决 <script setup> 中无法设置组件选项的问题。
html
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<script>
// ❌ 不能这样写(两个 script 不兼容)
</script>
正确方式:
html
<script setup>
import { ref } from 'vue'
defineOptions({
name: 'MyCounter',
inheritAttrs: false
})
const count = ref(0)
</script>
支持的选项:name, inheritAttrs, props, emits(但推荐用专用宏)等。
defineModel
简化 v-model 的实现。
传统方式(繁琐)
js
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const model = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
使用 defineModel
html
<script setup>
const model = defineModel()
// 直接读写 model
model.value = 'new value'
</script>
<template>
<input v-model="model" />
</template>
父组件使用:
html
<CustomInput v-model="parentValue" />
自动处理 modelValue prop 和 update:modelValue 事件,大幅简化代码。