Vue3实战:Composition API、Pinia与Router核心概念与应用指南
很多刚接触 Vue3 的同学会有这样的困惑明明官方文档都看了一遍Composition API、Pinia、Router 这些概念也大概知道是什么但一到实际项目就不知道怎么组织代码总感觉写出来的东西既不像 Vue2 那么直观又达不到 Vue3 应有的简洁和灵活。这其实不是你的问题而是学习路径的问题。Vue3 的核心价值不在于单个 API 的使用而在于它重新定义了前端开发的思考方式——从“选项式”的配置思维转向“组合式”的函数思维。今天我们就从实战角度把这三个核心概念真正吃透。1. 为什么说 Composition API 改变了 Vue 的编程范式很多人把 Composition API 简单理解为“把 data、methods、computed 写进 setup 函数里”这是最大的误解。Composition API 的本质是让你能用函数的方式来组织代码逻辑而不是被迫按照框架规定的选项结构来写。1.1 从“选项思维”到“函数思维”的转变在 Vue2 中一个功能相关的代码被分散在不同的选项里// Vue2 选项式 API export default { data() { return { count: 0, searchQuery: } }, computed: { filteredList() { return this.list.filter(item item.includes(this.searchQuery)) } }, methods: { increment() { this.count }, search() { // 搜索逻辑 } }, mounted() { this.fetchData() } }这种结构的问题在于当组件复杂时同一个功能的代码被分散在 data、methods、computed、mounted 等多个地方维护时需要上下滚动查看。Composition API 让你可以按功能而不是按选项来组织代码// Vue3 组合式 API import { ref, computed, onMounted } from vue export default { setup() { // 计数器功能 const count ref(0) const increment () count.value // 搜索功能 const searchQuery ref() const list ref([]) const filteredList computed(() list.value.filter(item item.includes(searchQuery.value)) ) const fetchData async () { // 获取数据 } onMounted(fetchData) return { count, increment, searchQuery, filteredList } } }1.2 逻辑复用的革命自定义组合函数Composition API 最强大的地方在于可以提取可复用的逻辑。比如我们可以把搜索功能抽象成一个独立的组合函数// composables/useSearch.js import { ref, computed } from vue export function useSearch(initialList []) { const searchQuery ref() const list ref(initialList) const filteredList computed(() list.value.filter(item item.toLowerCase().includes(searchQuery.value.toLowerCase()) ) ) const updateList (newList) { list.value newList } return { searchQuery, filteredList, updateList } }然后在多个组件中复用// 组件A import { useSearch } from /composables/useSearch export default { setup() { const { searchQuery, filteredList, updateList } useSearch([apple, banana]) return { searchQuery, filteredList } } } // 组件B import { useSearch } from /composables/useSearch export default { setup() { const { searchQuery, filteredList, updateList } useSearch([cat, dog]) return { searchQuery, filteredList } } }这种复用方式比 Vue2 的 mixin 更安全、更灵活因为每个组合函数都有独立的作用域不会出现命名冲突的问题。1.3 响应式系统的深度理解很多人对 ref 和 reactive 的使用场景感到困惑其实选择原则很简单ref用于基本类型string、number、boolean和需要保持引用的对象reactive用于纯对象且不需要重新赋值的场景import { ref, reactive } from vue // 适合用 ref 的情况 const count ref(0) const user ref({ name: John, age: 30 }) // 适合用 reactive 的情况 const form reactive({ username: , password: , remember: false }) // 修改方式的不同 count.value // ref 需要 .value form.username new name // reactive 直接赋值实际项目中我建议优先使用 ref因为它在组合函数中返回时更安全不容易丢失响应性。2. Pinia 不仅仅是 Vuex 的替代品Pinia 被很多人理解为 Vuex5但实际上它的设计理念比 Vuex 更先进。Pinia 的核心优势在于更好的 TypeScript 支持、更简洁的 API 设计和与 Composition API 的无缝集成。2.1 Store 设计的核心原则一个良好的 Store 应该遵循单一职责原则。不要创建一个巨大的 Store 来管理所有状态而是按业务模块拆分// stores/user.js import { defineStore } from pinia export const useUserStore defineStore(user, { state: () ({ userInfo: null, permissions: [], isLoggedIn: false }), getters: { userName: (state) state.userInfo?.name || , hasPermission: (state) (permission) state.permissions.includes(permission) }, actions: { async login(credentials) { const userData await api.login(credentials) this.userInfo userData.user this.permissions userData.permissions this.isLoggedIn true }, logout() { this.userInfo null this.permissions [] this.isLoggedIn false } } })// stores/app.js import { defineStore } from pinia export const useAppStore defineStore(app, { state: () ({ theme: light, sidebarCollapsed: false, loading: false }), actions: { toggleTheme() { this.theme this.theme light ? dark : light }, setLoading(loading) { this.loading loading } } })2.2 Option Store 与 Setup Store 的选择Pinia 支持两种定义 Store 的方式各有适用场景Option Store适合大多数场景export const useCounterStore defineStore(counter, { state: () ({ count: 0 }), getters: { double: (state) state.count * 2 }, actions: { increment() { this.count } } })Setup Store需要更复杂逻辑时export const useCounterStore defineStore(counter, () { const count ref(0) const double computed(() count.value * 2) function increment() { count.value } return { count, double, increment } })我建议新手先从 Option Store 开始等熟悉 Pinia 后再根据需要使用 Setup Store。2.3 Store 之间的通信和组合多个 Store 之间需要通信时不要直接相互导入和调用而是通过事件或高层 Store 来协调// stores/order.js export const useOrderStore defineStore(order, { actions: { async submitOrder() { // 提交订单前检查用户权限 const userStore useUserStore() if (!userStore.hasPermission(create_order)) { throw new Error(无权限创建订单) } // 设置加载状态 const appStore useAppStore() appStore.setLoading(true) try { // 提交订单逻辑 await api.submitOrder(this.orderData) } finally { appStore.setLoading(false) } } } })2.4 持久化存储的最佳实践对于需要持久化的数据如用户登录状态、主题设置建议使用 pinia-plugin-persistedstateimport { createPinia } from pinia import piniaPluginPersistedstate from pinia-plugin-persistedstate const pinia createPinia() pinia.use(piniaPluginPersistedstate) // Store 配置 export const useUserStore defineStore(user, { state: () ({ token: , userInfo: null }), persist: { key: user-data, paths: [token] // 只持久化 token } })3. Vue Router 4 的现代化路由管理Vue Router 4 为 Vue3 提供了更强大的路由能力特别是在类型安全和组合式 API 集成方面。3.1 路由配置的模块化组织大型项目的路由配置应该按模块拆分// router/index.js import { createRouter, createWebHistory } from vue-router const routes [ { path: /, component: () import(/layouts/MainLayout.vue), children: [ ...homeRoutes, ...userRoutes, ...productRoutes ] }, { path: /auth, component: () import(/layouts/AuthLayout.vue), children: authRoutes } ] export const router createRouter({ history: createWebHistory(), routes })// router/routes/user.js export const userRoutes [ { path: profile, name: user-profile, component: () import(/views/UserProfile.vue), meta: { requiresAuth: true } }, { path: settings, name: user-settings, component: () import(/views/UserSettings.vue), meta: { requiresAuth: true } } ]3.2 组合式 API 下的路由使用在组合式 API 中路由相关的操作更加直观import { useRoute, useRouter } from vue-router import { watch } from vue export default { setup() { const route useRoute() const router useRouter() // 获取路由参数 const userId computed(() route.params.id) // 响应路由参数变化 watch(() route.params.id, (newId) { fetchUserData(newId) }) // 编程式导航 const goToUserProfile (id) { router.push({ name: user-profile, params: { id } }) } // 替换当前路由不保留历史记录 const replaceToHome () { router.replace({ name: home }) } return { userId, goToUserProfile, replaceToHome } } }3.3 路由守卫的现代化写法路由守卫应该保持简洁和可维护// router/guards.js export function setupRouterGuards(router) { // 全局前置守卫 router.beforeEach((to, from) { const userStore useUserStore() // 检查是否需要登录 if (to.meta.requiresAuth !userStore.isLoggedIn) { return { name: login, query: { redirect: to.fullPath } } } // 页面标题设置 if (to.meta.title) { document.title ${to.meta.title} - 我的应用 } }) // 全局后置钩子 router.afterEach((to, from) { // 页面访问统计 trackPageView(to.fullPath) }) }3.4 动态路由的高级用法对于权限管理系统动态路由是必备功能// 动态添加路由 export function addDynamicRoutes(router, userPermissions) { const dynamicRoutes generateRoutesBasedOnPermissions(userPermissions) dynamicRoutes.forEach(route { router.addRoute(route) }) } // 基于权限生成路由 function generateRoutesBasedOnPermissions(permissions) { const routes [] if (permissions.includes(admin)) { routes.push({ path: /admin, component: () import(/views/AdminDashboard.vue), meta: { requiresAdmin: true } }) } if (permissions.includes(report_view)) { routes.push({ path: /reports, component: () import(/views/Reports.vue) }) } return routes }4. 三者的协同构建可维护的 Vue3 应用架构单独掌握每个技术点还不够关键是要理解它们如何协同工作。4.1 项目目录结构的最佳实践src/ ├── components/ # 通用组件 │ ├── ui/ # 基础UI组件 │ └── business/ # 业务组件 ├── composables/ # 组合函数 │ ├── useApi.js │ ├── useForm.js │ └── usePagination.js ├── stores/ # Pinia Store │ ├── user.js │ ├── app.js │ └── product.js ├── router/ # 路由配置 │ ├── index.js │ ├── routes/ │ └── guards.js ├── views/ # 页面组件 ├── utils/ # 工具函数 └── api/ # API 接口4.2 数据流的最佳实践在 Vue3 应用中清晰的数据流非常重要组件内部状态使用 ref/reactive组件间共享状态使用 Props/Events 或 provide/inject全局应用状态使用 Pinia Store服务端状态使用 TanStack Query 或 SWR复杂场景// 组件示例 export default { setup() { // 本地状态 const localFilter ref() // 从 Store 获取全局状态 const userStore useUserStore() const { userInfo } storeToRefs(userStore) // 使用组合函数 const { data, loading, error } useApi(/api/data) // 路由相关 const route useRoute() return { localFilter, userInfo, data, loading } } }4.3 错误处理和加载状态管理良好的错误处理能显著提升用户体验// composables/useAsync.js export function useAsync(fn) { const loading ref(false) const error ref(null) const data ref(null) const execute async (...args) { loading.value true error.value null try { data.value await fn(...args) } catch (err) { error.value err // 统一错误处理 handleError(err) } finally { loading.value false } } return { loading, error, data, execute } } // 在组件中使用 export default { setup() { const { loading, error, data, execute } useAsync(api.getUserList) onMounted(() execute()) return { loading, error, userList: data } } }4.4 性能优化要点Vue3 应用性能优化的关键点组件懒加载const UserProfile defineAsyncComponent(() import(/views/UserProfile.vue) )状态按需加载// 只在需要时加载 Store const userStore useUserStore() if (needUserInfo) { userStore.fetchUserInfo() }计算属性缓存const expensiveValue computed(() { // 复杂计算 return heavyCalculation(data.value) })监听器优化// 避免深层监听 watch(() props.item.id, (newId) { // 只在 id 变化时执行 }, { immediate: true })Vue3 的这套技术栈真正强大的地方在于它提供了一套完整的思想体系而不仅仅是一堆 API。当你真正理解组合式思维后会发现代码的组织方式变得更加自然和可预测。记住好的架构不是一开始就设计出来的而是在不断重构中逐步演化出来的。先从小的组合函数开始逐步构建出适合自己项目的模式。

相关新闻

告别格式转换烦恼:Blender 3MF插件让你的3D打印工作流无缝衔接

告别格式转换烦恼:Blender 3MF插件让你的3D打印工作流无缝衔接

告别格式转换烦恼:Blender 3MF插件让你的3D打印工作流无缝衔接 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat 你是否曾经在Blender中精心设计了一个完美的3D…

2026/10/19 1:19:01 阅读更多 →
【致敬奋斗者】2026武汉劳动保护用品展会定档

【致敬奋斗者】2026武汉劳动保护用品展会定档

【致敬奋斗者】2026武汉劳动保护用品展会定档:为每一位劳动者铸就最强“铠甲” 从智慧疏散到极限防护:2026武汉劳保展启幕,解码工业安全黑科技 锁定九月江城!2026武汉国际劳保展:构建后工业时代的平安防线 生命的重量…

2026/10/20 3:59:47 阅读更多 →
轻盈的力量:2026 武汉国际发泡材料技术工业展览会,重构未来工业的“呼吸感”

轻盈的力量:2026 武汉国际发泡材料技术工业展览会,重构未来工业的“呼吸感”

气泡里的工业魔法!2026武汉发泡展,揭秘材料进化的下一个十年减重还是控温?2026武汉发泡材料展定档:解码全场景“轻量化”逻辑锁定九月江城!2026武汉国际发泡材料展启幕:从实验室走向未来工厂轻盈的力量&…

2026/10/18 6:56:19 阅读更多 →

最新新闻

2026网络安全就业全景:岗位趋势、薪酬地图与技能风向

2026网络安全就业全景:岗位趋势、薪酬地图与技能风向

1. 为什么我会在年底啃这份招聘数据:调研背景与样本口径每年四季度都是观察次年就业市场最好的窗口期,因为各大公司的HC预算、校招指标、社招编制基本都在这个阶段定调。我做了近十年的安全行业职业发展相关调研,今年选了2025年10月到2026年1…

2026/10/20 12:47:34 阅读更多 →
AI论文写作全攻略:四款实用工具与高效降重、文献综述实操指南

AI论文写作全攻略:四款实用工具与高效降重、文献综述实操指南

毕业季又到了,我后台收到最多的私信就是“论文写不出来怎么办”。说实话,毕业论文这事儿,卡在最后一步的滋味确实难受。今年我实测了市面上主流的几款AI论文写作工具,也拉了几个刚答辩完的同学做了深度反馈,今天直接把…

2026/10/20 12:47:34 阅读更多 →
圆的性质第二讲:垂径定理、圆周角定理与圆内接四边形实战要点

圆的性质第二讲:垂径定理、圆周角定理与圆内接四边形实战要点

圆的性质是初中几何里最"有看头"的一块内容——结论密集、模型多样,而且和代数、三角都能搭上关系。云藏山鹰代数信息系统的几何模块里,圆的性质系列课程我已经带过好几轮了,这次把第二讲的教学手记整理成文:垂径定理怎…

2026/10/20 12:47:34 阅读更多 →
AI编码新王炸Augment实测:大项目重构、对比Cursor与避坑指南

AI编码新王炸Augment实测:大项目重构、对比Cursor与避坑指南

1. 为什么“AI 写代码”最近突然又换了一个主角1.1 先认识一下这位“新王炸”是谁这几年 AI 编码工具的更新频率,说实话已经快到让人麻木的程度。今天这个大模型说自己的代码能力第一,明天那个编辑器说自己能自动改完一个项目,用户嘴上说“好…

2026/10/20 12:47:34 阅读更多 →
配电网重构MISOCP建模:二阶锥松弛与MATLAB实战

配电网重构MISOCP建模:二阶锥松弛与MATLAB实战

简介:本资源是一套基于混合整数二阶锥规划(MISOCP)求解配电网重构问题的完整MATLAB实现代码,面向电力系统优化、智能配电网研究方向的研究生、科研人员及工程技术人员。针对传统启发式或智能算法在全局最优性与收敛性上的局限&…

2026/10/20 12:47:34 阅读更多 →
提示词模板化:从基础到高级的Prompt Engineering实战指南

提示词模板化:从基础到高级的Prompt Engineering实战指南

1. 为什么要把提示词做成模板:从重复劳动到可复用资产先讲一个我自己的经历。早期用对话式AI干活的时候,每次都是临时想提示词,想到哪写到哪:“帮我总结一下这段文字”“写一个产品介绍,要专业一点”。这种随手写的做法…

2026/10/20 12:46:33 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →