FORMA

工程化实践

SFC 拆分、自定义指令、插件与调试等工程化话题。构建工具见 生态 · Vite

Vue 的工程化实践涵盖组件设计、自定义指令、插件开发、跨框架复用、全局 API 变更以及调试工具,帮助团队构建可维护、可扩展的大型应用。

一、Vue 单文件组件(SFC)的设计模式

SFC 将模板、逻辑、样式聚合在一个 .vue 文件中,但当组件变得庞大时,需要合理的拆分策略。

1. 大型组件拆分策略

策略实现方式适用场景优缺点
拆分为多个子组件将可复用的 UI 片段(表格、弹窗、表单域)抽离为独立组件UI 结构复杂、存在明显边界✅ 组件职责单一,易于复用;❌ 组件间 props/emit 通信增多
使用 composable 组织逻辑将业务逻辑封装到组合式函数中,SFC 中仅保留模板和简单数据流逻辑复杂、UI 相对简单✅ 逻辑复用方便,模板轻量;❌ 需理解 composable 模式

实际建议:两者常结合使用。例如:UserProfile.vue 内部拆分为 UserHeaderUserStats 子组件,数据获取逻辑则放入 useUserData composable。

2. 模板限制与解决方案

  • 避免在模板中写过重逻辑:如复杂的三元表达式、深层属性访问、数组过滤等应移到计算属性中。
    vue
    <template>
      <!-- ❌ 坏 -->
      <div>{{ user?.address?.city?.toUpperCase() || "Unknown" }}</div>
      <!-- ✅ 好 -->
      <div>{{ displayCity }}</div>
    </template>
    <script setup>
    const displayCity = computed(() => user.value?.address?.city?.toUpperCase() ?? "Unknown");
    </script>
    
  • 模板中避免副作用:模板内不应调用修改数据的方法,只做展示。

二、自定义指令

自定义指令允许对 DOM 元素进行底层操作,封装通用 DOM 行为。

1. 指令的生命周期钩子

Vue 3 指令钩子(与组件生命周期类似):

  • created:在绑定属性前调用(很少用)。
  • beforeMount:第一次调用 mounted 前。
  • mounted:元素挂载后,可用于操作 DOM。
  • beforeUpdate:更新前。
  • updated:更新后。
  • beforeUnmount:卸载前。
  • unmounted:卸载后。

常用示例(v-focus):

js
const vFocus = {
  mounted: (el) => el.focus(),
  updated: (el) => {
    if (el.shouldFocus) el.focus();
  },
};

2. 全局指令 vs 局部注册

  • 局部注册:在组件内通过 directives 选项(或 <script setup> 中以 v 开头的变量)注册,仅限当前组件。
    vue
    <script setup>
    const vMyDirective = { mounted: (el) => {...} };
    </script>
    <template>
      <input v-my-directive />
    </template>
    
  • 全局注册:通过 app.directive(name, definition) 在整个应用中可用。
    js
    const app = createApp(App);
    app.directive("focus", { mounted: (el) => el.focus() });
    

3. 实际应用场景

  • 权限控制指令(v-permission:根据用户角色显示/隐藏元素。
    js
    app.directive("permission", {
      mounted(el, binding) {
        const requiredRoles = binding.value;
        if (!hasAnyRole(requiredRoles)) el.remove();
      },
    });
    
  • 防抖指令(v-debounce:包装点击或输入事件。
  • 懒加载指令(v-lazy:使用 IntersectionObserver 加载图片。

三、自定义插件

插件通过 app.use() 安装,用于向应用注入全局功能。

实现一个插件

js
// plugins/i18n.js
export default {
  install(app, options) {
    // 注入全局属性
    app.config.globalProperties.$t = (key) => translations[key] || key;
    // 注册全局组件
    app.component("MyButton", MyButton);
    // 注册全局指令
    app.directive("focus", { mounted: (el) => el.focus() });
    // 提供依赖注入
    app.provide("i18n", options);
  },
};

使用:

js
import i18nPlugin from "./plugins/i18n";
app.use(i18nPlugin, { locale: "zh-CN" });

插件中注入全局属性的类型扩展(TypeScript)

ts
declare module "vue" {
  interface ComponentCustomProperties {
    $t: (key: string) => string;
  }
}

四、Vue 与 Web Components 互操作

Vue 3 内置了对 Web Components 的支持,可以将 Vue 组件编译为原生自定义元素,可在任何框架(或原生 HTML)中使用。

使用 defineCustomElement 打包 Vue 组件

js
import { defineCustomElement } from "vue";
import MyComponent from "./MyComponent.vue";

const MyElement = defineCustomElement(MyComponent);
customElements.define("my-component", MyElement);

现在可以在 HTML 中直接使用 <my-component></my-component>

注意事项

  • 样式默认会封装在 Shadow DOM 中,支持样式隔离。
  • Props 通过 HTML 属性传递(非字符串需手动转换)。
  • 插槽支持,但不支持作用域插槽。
  • 适合跨框架复用(如 React、Angular 中使用 Vue 组件)。

五、全局 API 变更(Vue 2 → Vue 3)

Vue 3 改变了全局 API 的设计,以支持多应用实例隔离。

Vue 2Vue 3说明
Vue.prototype.$http = ...app.config.globalProperties.$http = ...全局属性挂载到 app 实例,避免污染 Vue 构造函数
Vue.component('my-comp', {...})app.component('my-comp', {...})组件注册限定在特定 app 内
Vue.directive('focus', {...})app.directive('focus', {...})指令注册同理
Vue.use(plugin, options)app.use(plugin, options)插件作用域为 app
new Vue({...})createApp({...})返回 app 实例,支持多应用

优势

  • 支持在同一个页面中运行多个 Vue 应用(微前端场景),它们之间不会相互干扰。
  • 便于测试(每个测试可以创建独立的 app)。

六、开发调试工具:Vue DevTools

Vue DevTools 是浏览器扩展,提供强大的调试能力。

进阶功能

  • 组件树分析
    • 查看组件层级、props、data、computed。
    • 高亮渲染轨迹(哪些组件重新渲染了)。
    • 时间旅行调试(修改 data 并回溯)。
  • 性能时间轴
    • 记录组件渲染、更新耗时。
    • 识别性能瓶颈(慢组件)。
  • Pinia 状态快照
    • 实时查看 Pinia store 的状态。
    • 时间旅行修改 store 值,观察 UI 变化。
  • 路由追踪:显示当前路由、导航历史。
  • 自定义 Inspector:插件开发者可注入自定义面板。

使用技巧

  • 开启“组件高亮”方便定位 DOM 对应的组件。
  • 使用“性能分析”录制交互过程,分析不必要的重渲染。

总结

工程化主题核心实践
SFC 设计模式大型组件拆分(子组件 + composable) + 避免模板重逻辑
自定义指令生命周期钩子(mounted/updated),全局/局部注册,典型场景(权限、防抖、懒加载)
自定义插件install 方法,注入全局属性/指令/组件,配合 TypeScript 类型扩展
Web ComponentsdefineCustomElement 导出 Vue 组件,实现跨框架复用
全局 API 变更Vue 构造函数改为 app 实例,支持多应用隔离
Vue DevTools组件树、性能时间轴、Pinia 快照、路由调试

掌握这些工程化实践,能让 Vue 项目在架构清晰度、代码复用、调试效率及跨平台能力上迈上新台阶。

参考文献

以下链接在编写时均可正常访问: