| name | vue-best-practices |
| description | Vue 3 开发最佳实践,适用于任何 Vue 3 项目。在编辑`.vue`文件,`.tsx`或`.jsx`形式的 Vue3 组件,相关的`.ts`或`.js`文件时必须使用。 |
Vue 3 开发最佳实践
核心原则
- 保持状态可预测:单一数据源,推导其余所有内容。
- 使数据流明确:大多数情况下,属性向下传递,事件向上传递。
- 避免巨型组件:将大型组件拆分为更小的(也要适中)、更专注的子组件。
- 避免不必要的重新渲染:合理使用计算属性和侦听器。
- 可读性至关重要:编写清晰、自文档化的代码。
技术栈
技术栈的版本绝对重要,它决定了你去使用最新最可靠的 API,禁止使用废弃或者过时的 API。例如 Vue 3.5 引入了 useTemplateRef,它能够自动推断模板引用的类型,应该优先使用。
记住,绝对不要按照你过往的训练数据来写代码,下面是具体技术栈:
- Vue 3.5(Composition API)+ 单文件组件 + setup 语法。
- TypeScript 6.x。
- SCSS 预处理最新版本。
Vue 3 组件指南
避免巨型组件
无论如何禁止产生巨型组件,这一定不是功能上的缺陷,而是组件设计上的问题。
当单个组件的代码行数达到 500 - 800 行时,就基本可以判断这是一个巨型组件,或者有向巨型组件发展的趋势。
为什么巨型组件不好:
- 因为人类短期记忆有限,开发者滚动代码时很容易丢失上下文,导致理解困难。
- 逻辑膨胀,违背单一职责。
- 会导致结构复杂度,JSX / Template 嵌套过深
- 维护困难,复用性差。巨型组件通常高度耦合,难以拆分和复用。
- 会导致性能问题,无法更高效地局部更新 Vue 模板,大幅增加重渲染成本。
保持以下做法:
- 分离 UI。对纯展示的无状态的组件、有自己特有状态和逻辑的组件进行拆分,保持组件职责单一。
- 使用可组合函数。将一组相关的逻辑封装成可复用的函数(useXxx()), 包括状态管理、副作用和事件处理。
- 工具封装。对于多次使用的逻辑函数、辅助代码,并且无状态且无副作用的,进行工具封装。
- 状态提升。对于多个组件共享的状态,提升到它们的最近公共祖先组件中管理,避免 props 层层传递,比如使用 Vue 的 provide/inject 或者 Pinia store。
应用客观的拆分触发条件。如果满足以下任一条件,则拆分组件:
- 它同时拥有编排/状态逻辑以及多个部分的大量呈现性标记。
- 它包含3个以上不同的UI部分(例如:表单、筛选器、列表、页脚/状态)。
- 存在重复使用的模板块或可复用的部分(如项目行、卡片、列表条目)。
入口/根和路由视图规则:
- 保持入口/根和路由视图组件精简:应用外壳/布局、提供者连接和功能组合。
- 当功能包含独立部分时,不要将完整的功能实现放在入口/根/视图组件中。
代码可读性
- 清晰的命名。变量、函数、组件和文件应该有描述性的名称,准确反映它们的目的和行为。
- 一致的风格。遵循一致的代码风格和约定。
- 避免过度抽象。过度抽象会增加理解和调试的难度,保持代码简单直接。
- 使用注释。在复杂的逻辑或不直观的部分添加注释,但避免过度注释,代码应该尽可能自解释。
保证性能
-
使用异步组件。对重量级的、不常用的、按需使用的组件使用异步组件来懒加载。
-
避免频繁渲染整个模板。 禁止高频触发的事件、动画、定时器导致整个模板重新渲染的情况,比如使用鼠标拖拽滑块时只想更新滑块的 UI 状态,却导致整个页面重新渲染,哪怕看起来页面其它部分没有变化,Vue 也会重新执行整个模板的渲染函数,导致性能问题。
-
对列表渲染绑定key。
-
减少响应式系统开销。
- 避免什么变量都定义成响应式对象,要根据实际业务需求来判断。
- 对于不需要响应式的属性,使用
shallowRef 或 shallowReactive。
-
防止内存泄露。
- 在组件销毁时清理定时器、事件监听器和其他副作用。
- 使用
onUnmounted、onBeforeUnmount、onScopeDispose等生命周期钩子来执行清理逻辑。
-
禁止对响应式数据进行拷贝中间操作. 保持响应式数据在组件间直传,除了特殊需求(例如需要保留初始数据进行重置, 或者确实有拷贝副本的需求), 避免数据拷贝操作, 此操作需要额外实现数据同步机制, 不仅麻烦降低了组件的可维护性, 而且还降低了性能.
偏好
- 使用
useTemplateRef 替代 ref 来获取模板引用。