如果把一个 Vue 3 项目比作一座建筑,那么组件化设计、状态管理和目录工程化就是它的基石。很多团队在项目初期只关注页面能不能跑起来,等到业务规模膨胀后再回头重构,成本会成倍增加。本文围绕内容管理与学习这条主线,系统梳理 Vue 3 工程化实践中最核心的几块内容,帮助你搭建一个可持续维护的项目骨架。

组件化设计:Vue 3 工程化的第一块基石
组件化的本质不是把页面切碎,而是按照职责边界划分代码。Vue 3 的 Composition API 让逻辑复用摆脱了 Options API 的选项式限制,同一个功能关注点的代码可以集中在一起,这为更细粒度的组件拆分提供了条件。一个经验法则是:页面级组件只负责数据编排和布局,业务组件负责交互,基础组件保持无状态、可配置。
以一个内容管理后台的文章编辑模块为例,可以拆分为编辑器组件、分类选择器、标签管理器和发布状态栏。每个组件只暴露必要的 props 和 events,父组件通过组合它们来完成页面逻辑。这样的拆分让每个文件的代码量控制在合理范围,后续修改某一个功能时不容易牵一发而动全身。
<template>
<div class="article-editor">
<CategorySelector v-model="categoryId" />
<TagManager v-model:tags="tags" />
<RichEditor v-model="content" />
<PublishBar :status="status" @publish="handlePublish" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import CategorySelector from './CategorySelector.vue'
import TagManager from './TagManager.vue'
import RichEditor from './RichEditor.vue'
import PublishBar from './PublishBar.vue'
const categoryId = ref(null)
const tags = ref([])
const content = ref('')
const status = ref('draft')
function handlePublish() {
// 提交逻辑集中在页面级组件中
console.log({ categoryId, tags, content })
}
</script>需要注意的是,组件拆分并非越细越好。过度拆分会导致 props 传递层级过深、事件冒泡链冗长,反而增加理解成本。当发现某个组件需要透传七八个 props 给子组件时,通常说明职责边界划错了,应该重新审视分层。
状态管理:从 Pinia 选型到实践
Vue 2 时代 Vuex 几乎是唯一选择,而 Vue 3 官方推荐 Pinia。Pinia 去掉了 mutation 概念,天然支持 Composition API,模块化也更自然——每个 store 就是一个独立函数,类型推导和代码分割都很友好。对于内容管理类应用,状态大致分为三类:服务端数据缓存、用户会话信息、界面交互状态,三者最好放在不同的 store 中管理。
一个常见的实践误区是把所有东西都塞进全局 store。实际上,只有跨页面、跨组件共享的状态才值得进入 Pinia,表单临时状态、弹窗开关这类局部状态留在组件内部即可。判断标准很简单:问自己这个状态是否会被兄弟模块读取,如果答案是否定的,就不要全局化。
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 文章内容仓库
export const useArticleStore = defineStore('article', () => {
const articles = ref([])
const loading = ref(false)
async function fetchArticles() {
loading.value = true
try {
const res = await fetch('/api/articles')
articles.value = await res.json()
} finally {
loading.value = false
}
}
return { articles, loading, fetchArticles }
})对于服务端数据,还可以进一步引入请求层缓存策略,比如在 store 中记录数据时间戳,命中缓存时跳过请求。这种模式在内容管理后台中能显著减少重复请求,同时保持数据新鲜度可控。
组合式函数与工程目录规划
Composition API 带来的最大红利是逻辑复用可以脱离组件存在。把异步请求、防抖、分页这类通用逻辑封装成组合式函数(composables),既能在多个项目间复用,也让单元测试变得简单——不需要挂载组件就能直接测试逻辑。命名上建议统一以 use 开头,比如 useFetch、usePagination、useDebounce,团队内形成约定后可读性会大幅提升。
import { ref, onMounted, onUnmounted } from 'vue'
// 通用分页逻辑封装
export function usePagination(fetchFn, pageSize = 20) {
const page = ref(1)
const total = ref(0)
const list = ref([])
const loading = ref(false)
async function load() {
loading.value = true
try {
const res = await fetchFn({ page: page.value, pageSize })
list.value = res.items
total.value = res.total
} finally {
loading.value = false
}
}
function nextPage() {
page.value++
return load()
}
onMounted(load)
return { page, total, list, loading, load, nextPage }
}目录结构上,推荐的思路是按功能域而非技术类型组织。比如 src/modules/article/ 下同时放置该模块的组件、store 和 API 封装,而不是把所有组件堆进 components、所有接口堆进 api。这样做的好处是删除或迁移某个业务模块时只需处理一个目录,不会在全局各处留下孤儿文件。共享的组合式函数和基础组件则放在 src/composables 与 src/components 中,边界清晰。
最后,工程化还包括配套的规范建设:ESLint 配合 vue3 插件约束代码风格,提交信息规范化方便追溯,Vite 的按需引入减少包体积。这些工具看似琐碎,却决定了项目半年后是井然有序还是混沌一片。持续学习的关键在于动手实践——从一个小模块开始应用上述模式,逐步推广到整个项目,工程能力自然会在迭代中沉淀下来。