恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Vue 3 组合式 API 入门教程:从 Options API 到 Composition API

  • 首页
  • 资讯中心
  • /
  • Vue 3 组合式 API 入门教程:从 Options API 到 Composition API

相关资讯

FreeRTOS移植实战:从硬件适配到内核配置的完整指南 2026/8/19 6:40:28
基于ESP32与GP2Y1014AU0F的PM2.5监测仪制作指南 2026/8/19 6:40:28
CORE-Bench:面向智能体编程的新一代代码检索基准与实战指南 2026/8/19 6:40:28

最新资讯

GUI智能体感知融合:像素与结构信息的权衡与诊断
NVIDIA Profile Inspector 完整上手教程:免费解锁显卡驱动里上百个隐藏设置
ESP32-S3驱动WS2812B点阵屏:从硬件选型到瀑布光效算法实现
基于MAX32660与墨水屏的超低功耗温度监测系统设计
Windows系统文件修复指南:System32文件夹替换的灾难与安全恢复方案
NVIDIA Profile Inspector 完整上手教程:解锁驱动隐藏设置,游戏性能提升可达 30%

今日推荐

Windows 安卓应用安装终极方案:5分钟上手免费APK安装器,三步告别模拟器
WarcraftHelper 魔兽争霸3优化实战指南
抖音批量下载实战手册:用douyin-downloader把6小时手工劳动压缩到15分钟

本周热门

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码
【双层规划,节点出清价,绿证交易,CVaR方法】两级电力市场环境下计及风险的省间交易商最优购电模型附Matlab代码
隐式mpc+自适应mpc+时变mpc,线性时变模型预测控制附Simulink仿真

本月精选

如何用DamaiHelper实现演唱会门票的智能自动化抢购:完整技术解决方案指南
第4篇:59 倍性能差距的索引瓶颈定位——一次教科书级的全表扫描调优
终极歌词批量下载神器:5分钟解决离线音乐库歌词同步难题

Vue 3 组合式 API 入门教程:从 Options API 到 Composition API

发布时间:2026/8/19 6:45:29
Vue 3 组合式 API 入门教程:从 Options API 到 Composition API 前言Vue 3 引入了全新的组合式 APIComposition API它解决了大型组件中逻辑分散的问题让代码更易组织和复用。本教程将带你从零开始掌握组合式 API 的核心用法并通过实战项目巩固所学知识。一、为什么需要组合式 API1.1 Options API 的痛点在 Vue 2 的 Options API 中组件代码按选项类型组织script export default { data() { return { searchKeyword: , userList: [], cartItems: [] } }, computed: { filteredUsers() { /* 搜索相关逻辑 */ }, cartTotal() { /* 购物车相关逻辑 */ } }, methods: { searchUsers() { /* 搜索相关逻辑 */ }, addToCart() { /* 购物车相关逻辑 */ }, removeFromCart() { /* 购物车相关逻辑 */ } }, mounted() { this.searchUsers() this.loadCart() } } /script问题搜索功能的逻辑分散在 data、computed、methods、mounted 中当组件变大后很难追踪一个完整的功能逻辑。1.2 Composition API 的优势组合式 API 按功能组织代码script setup // 搜索功能 —— 所有相关代码集中在一起 const { searchKeyword, filteredUsers, searchUsers } useSearch() // 购物车功能 —— 所有相关代码集中在一起 const { cartItems, cartTotal, addToCart, removeFromCart } useCart() /script对比项Options APIComposition API代码组织按选项类型按功能逻辑逻辑复用mixins易冲突自定义组合式函数TypeScript支持较弱原生支持代码量较少样板稍多但更清晰适用场景小型组件中大型组件二、环境搭建2.1 创建 Vue 3 项目# 使用 Vite 创建推荐npmcreate vitelatest my-vue-app ----templatevuecdmy-vue-appnpminstallnpmrun dev# 使用 Vue CLInpminstall-gvue/cli vue create my-vue-app2.2 项目结构my-vue-app/ ├── src/ │ ├── components/ │ ├── composables/ # 组合式函数目录 │ ├── App.vue │ └── main.js ├── index.html ├── package.json └── vite.config.js三、script setup语法script setup是组合式 API 的编译时语法糖让代码更简洁。3.1 基本用法script setup import { ref, computed } from vue // 响应式数据 const count ref(0) // 计算属性 const doubleCount computed(() count.value * 2) // 方法 function increment() { count.value } /script template div p计数: {{ count }}/p p双倍: {{ doubleCount }}/p button clickincrement1/button /div /template3.2 与普通script的区别!-- 普通 script需要 return -- script import { ref } from vue export default { setup() { const count ref(0) return { count } // 必须返回才能在模板中使用 } } /script !-- script setup自动暴露 -- script setup import { ref } from vue const count ref(0) // 自动暴露给模板 /script四、核心 API 详解4.1 ref —— 基本类型响应式script setup import { ref } from vue // 字符串 const message ref(Hello Vue 3) // 数字 const count ref(0) // 布尔值 const isVisible ref(false) // 对象ref 也可以包装对象 const user ref({ name: 张三, age: 25 }) // 修改值注意 .value function updateMessage() { message.value Updated! } function updateUser() { // 直接修改 ref 包装的对象属性 user.value.name 李四 // 或整体替换 user.value { name: 王五, age: 30 } } /script template !-- 模板中不需要 .value -- p{{ message }}/p p{{ count }}/p p{{ user.name }} - {{ user.age }}/p /template注意在script中访问 ref 需要.value在template中不需要。4.2 reactive —— 对象响应式script setup import { reactive } from vue // reactive 用于对象/数组不需要 .value const state reactive({ user: { name: 张三, age: 25 }, settings: { theme: light, language: zh-CN } }) // 直接修改 function updateName() { state.user.name 李四 } // 注意reactive 不能替换整个对象 function wrongReplace() { // state reactive({...}) // ❌ 这样会失去响应性 } // 正确做法逐个属性修改或用 Object.assign function correctReplace() { Object.assign(state.user, { name: 王五, age: 30 }) } /script4.3 ref vs reactive 选择// 推荐使用 ref因为它更一致constnameref(张三)// 基本类型constuserref({age:25})// 对象constlistref([])// 数组// ref 可以整体替换reactive 不行user.value{name:李四}// ✅ ref 可以// state { name: 李四 } // ❌ reactive 不行// 解构ref 解构不丢失响应性template 中自动 unwrap// reactive 解构会丢失响应性conststatereactive({a:1,b:2})let{a,b}state// ❌ a, b 不再是响应式// 正确做法使用 toRefsimport{toRefs}fromvueconst{a,b}toRefs(state)// ✅ 保持响应性4.4 computed —— 计算属性script setup import { ref, computed } from vue const firstName ref(张) const lastName ref(三) // 只读计算属性 const fullName computed(() ${firstName.value}${lastName.value}) // 可写计算属性 const fullNameWritable computed({ get() { return ${firstName.value}${lastName.value} }, set(newValue) { const names newValue.split( ) firstName.value names[0] || lastName.value names[1] || } }) // 计算属性依赖其他计算属性 const greeting computed(() Hello, ${fullName.value}!) // 列表过滤 const items ref([ { id: 1, name: 苹果, price: 5 }, { id: 2, name: 香蕉, price: 3 }, { id: 3, name: 橙子, price: 8 } ]) const minPrice ref(0) const filteredItems computed(() items.value.filter(item item.price minPrice.value) ) /script4.5 watch —— 侦听器script setup import { ref, watch, watchEffect } from vue const keyword ref() const page ref(1) // 1. 侦听单个 ref watch(keyword, (newValue, oldValue) { console.log(关键词从 ${oldValue} 变为 ${newValue}) }) // 2. 侦听多个数据源 watch([keyword, page], ([newKeyword, newPage], [oldKeyword, oldPage]) { console.log(关键词: ${newKeyword}, 页码: ${newPage}) }) // 3. 侦听对象属性需要 getter 函数 const user ref({ name: 张三, age: 25 }) watch( () user.value.age, (newAge, oldAge) { console.log(年龄从 ${oldAge} 变为 ${newAge}) } ) // 4. 深度侦听侦听对象内部变化 watch( user, (newUser) { console.log(用户信息变化:, newUser) }, { deep: true } ) // 5. 立即执行 watch( keyword, (newVal) { console.log(立即执行一次:, newVal) }, { immediate: true } ) // 6. watchEffect —— 自动追踪依赖立即执行 watchEffect(() { console.log(当前关键词: ${keyword.value}, 页码: ${page.value}) // 自动追踪 keyword 和 page任一变化都会重新执行 }) /script4.6 生命周期钩子script setup import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from vue // 对应 Vue 2 的 beforeCreate / created直接在 setup 中写 console.log(组件初始化) onBeforeMount(() { console.log(挂载前) }) onMounted(() { console.log(已挂载可以访问 DOM) // 适合初始化数据请求、添加事件监听、初始化第三方库 }) onBeforeUpdate(() { console.log(更新前) }) onUpdated(() { console.log(已更新) }) onBeforeUnmount(() { console.log(卸载前) // 适合清除定时器、移除事件监听 }) onUnmounted(() { console.log(已卸载) }) /script五、组件通信5.1 父传子 —— defineProps!-- 子组件 Child.vue -- script setup // 方式一运行时声明 const props defineProps({ title: String, count: { type: Number, default: 0 }, items: { type: Array, default: () [] } }) // 方式二TypeScript 类型声明推荐 // const props defineProps{ // title: string // count?: number // items?: string[] // }() /script template div h2{{ title }}/h2 p计数: {{ count }}/p ul li v-foritem in items :keyitem{{ item }}/li /ul /div /template!-- 父组件 -- script setup import Child from ./Child.vue /script template Child title用户列表 :count5 :items[张三, 李四, 王五] / /template5.2 子传父 —— defineEmits!-- 子组件 -- script setup const emit defineEmits([update, delete]) function handleClick() { emit(update, { id: 1, name: 张三 }) } function handleDelete() { emit(delete, 1) } /script template button clickhandleClick更新/button button clickhandleDelete删除/button /template!-- 父组件 -- script setup import Child from ./Child.vue function handleUpdate(data) { console.log(收到更新:, data) } function handleDelete(id) { console.log(删除 ID:, id) } /script template Child updatehandleUpdate deletehandleDelete / /template5.3 双向绑定 —— defineModel!-- 子组件 -- script setup // Vue 3.4 推荐使用 defineModel const modelValue defineModel() function updateValue() { modelValue.value 新值 } /script template input v-modelmodelValue / button clickupdateValue设为新值/button /template!-- 父组件 -- script setup import { ref } from vue import Child from ./Child.vue const text ref(初始值) /script template Child v-modeltext / p父组件值: {{ text }}/p /template5.4 暴露方法 —— defineExpose!-- 子组件 -- script setup import { ref } from vue const count ref(0) function reset() { count.value 0 } function increment() { count.value } // 暴露给父组件 defineExpose({ reset, increment, count }) /script!-- 父组件 -- script setup import { ref, onMounted } from vue import Child from ./Child.vue const childRef ref(null) onMounted(() { // 通过 ref 调用子组件方法 childRef.value.increment() }) function handleReset() { childRef.value.reset() } /script template Child refchildRef / button clickhandleReset重置子组件/button /template六、组合式函数 —— 逻辑复用6.1 创建组合式函数组合式函数是 Vue 3 中复用逻辑的推荐方式命名约定以use开头// composables/useCounter.jsimport{ref,computed}fromvueexportfunctionuseCounter(initialValue0,step1){constcountref(initialValue)constdoublecomputed(()count.value*2)functionincrement(){count.valuestep}functiondecrement(){count.value-step}functionreset(){count.valueinitialValue}return{count,double,increment,decrement,reset}}6.2 使用组合式函数script setup import { useCounter } from /composables/useCounter const { count, double, increment, decrement, reset } useCounter(10, 2) /script template div p计数: {{ count }}/p p双倍: {{ double }}/p button clickincrement{{ 2 }}/button button clickdecrement-{{ 2 }}/button button clickreset重置/button /div /template6.3 实用组合式函数示例useFetch —— 数据请求// composables/useFetch.jsimport{ref,watchEffect}fromvueexportfunctionuseFetch(url){constdataref(null)consterrorref(null)constloadingref(false)asyncfunctionfetchData(){loading.valuetrueerror.valuenulltry{constresponseawaitfetch(url.value||url)if(!response.ok)thrownewError(HTTP${response.status})data.valueawaitresponse.json()}catch(err){error.valueerr.message}finally{loading.valuefalse}}// 如果 url 是 ref自动重新请求if(typeofurlobjecturl.value!undefined){watchEffect(fetchData)}else{fetchData()}return{data,error,loading,refresh:fetchData}}useLocalStorage —— 本地存储// composables/useLocalStorage.jsimport{ref,watch}fromvueexportfunctionuseLocalStorage(key,defaultValue){conststoredlocalStorage.getItem(key)constdataref(stored?JSON.parse(stored):defaultValue)watch(data,(newVal){localStorage.setItem(key,JSON.stringify(newVal))},{deep:true})returndata}useMouse —— 鼠标位置追踪// composables/useMouse.jsimport{ref,onMounted,onUnmounted}fromvueexportfunctionuseMouse(){constxref(0)constyref(0)functionupdate(event){x.valueevent.clientX y.valueevent.clientY}onMounted((){window.addEventListener(mousemove,update)})onUnmounted((){window.removeEventListener(mousemove,update)})return{x,y}}6.4 在组件中使用script setup import { useFetch } from /composables/useFetch import { useLocalStorage } from /composables/useLocalStorage import { useMouse } from /composables/useMouse // 数据请求 const { data: users, loading, error, refresh } useFetch(/api/users) // 本地存储 const theme useLocalStorage(theme, light) // 鼠标位置 const { x, y } useMouse() /script template div !-- 数据请求 -- div v-ifloading加载中.../div div v-else-iferror错误: {{ error }}/div ul v-else li v-foruser in users :keyuser.id{{ user.name }}/li /ul button clickrefresh刷新/button !-- 主题切换 -- button clicktheme theme light ? dark : light 当前主题: {{ theme }} /button !-- 鼠标位置 -- p鼠标位置: {{ x }}, {{ y }}/p /div /template七、实战Todo List 应用!-- components/TodoApp.vue -- script setup import { ref, computed } from vue import { useLocalStorage } from /composables/useLocalStorage // 从本地存储恢复 const todos useLocalStorage(todos, []) const newTodoText ref() const filter ref(all) // 添加 function addTodo() { const text newTodoText.value.trim() if (!text) return todos.value.push({ id: Date.now(), text, done: false, createdAt: new Date().toISOString() }) newTodoText.value } // 删除 function removeTodo(id) { todos.value todos.value.filter(t t.id ! id) } // 切换完成状态 function toggleTodo(id) { const todo todos.value.find(t t.id id) if (todo) todo.done !todo.done } // 清除已完成 function clearCompleted() { todos.value todos.value.filter(t !t.done) } // 过滤后的列表 const filteredTodos computed(() { switch (filter.value) { case active: return todos.value.filter(t !t.done) case completed: return todos.value.filter(t t.done) default: return todos.value } }) // 统计 const remaining computed(() todos.value.filter(t !t.done).length) const total computed(() todos.value.length) /script template div classtodo-app h2Todo List/h2 !-- 输入 -- div classinput-row input v-modelnewTodoText keyup.enteraddTodo placeholder输入待办事项... / button clickaddTodo添加/button /div !-- 过滤 -- div classfilter-row button :class{ active: filter all } clickfilter all 全部 ({{ total }}) /button button :class{ active: filter active } clickfilter active 未完成 ({{ remaining }}) /button button :class{ active: filter completed } clickfilter completed 已完成 ({{ total - remaining }}) /button /div !-- 列表 -- ul classtodo-list li v-fortodo in filteredTodos :keytodo.id input typecheckbox :checkedtodo.done changetoggleTodo(todo.id) / span :class{ done: todo.done }{{ todo.text }}/span button clickremoveTodo(todo.id)删除/button /li /ul button v-iftotal - remaining 0 clickclearCompleted 清除已完成 /button /div /template style scoped .todo-app { max-width: 500px; margin: 0 auto; padding: 20px; } .input-row { display: flex; gap: 8px; margin-bottom: 16px; } .input-row input { flex: 1; padding: 8px; } .filter-row { display: flex; gap: 8px; margin-bottom: 16px; } .filter-row button { padding: 4px 12px; } .filter-row button.active { background: #42b883; color: white; } .todo-list { list-style: none; padding: 0; } .todo-list li { display: flex; align-items: center; gap: 8px; padding: 8px 0; } .todo-list li .done { text-decoration: line-through; color: #999; } .todo-list li button { margin-left: auto; } /styleAPI 速查表API用途示例ref()创建响应式数据const count ref(0)reactive()创建响应式对象const state reactive({...})computed()计算属性const double computed(() count.value * 2)watch()侦听特定数据watch(count, (newVal) {...})watchEffect()自动追踪依赖watchEffect(() { console.log(count.value) })onMounted()挂载后钩子onMounted(() { fetchData() })onUnmounted()卸载前钩子onUnmounted(() { clearInterval(timer) })defineProps()接收父组件数据const props defineProps({...})defineEmits()定义事件const emit defineEmits([...])defineModel()双向绑定const value defineModel()defineExpose()暴露方法defineExpose({ method })toRefs()解构保持响应性const { a, b } toRefs(state)总结本教程涵盖了 Vue 3 组合式 API 的核心内容设计理念理解从 Options API 到 Composition API 的演进script setup更简洁的语法糖核心 APIref、reactive、computed、watch、生命周期组件通信props、emits、model、expose逻辑复用组合式函数useFetch、useLocalStorage、useMouse实战项目完整的 Todo List 应用组合式 API 是 Vue 3 最重要的特性之一它让代码组织更加灵活、逻辑复用更加简单。建议在实际项目中多加练习逐步从 Options API 过渡到 Composition API。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号