Vue3 + ElementPlus 最佳实践

12 人参与

在企业级后台系统的开发中,Vue 3 与 ElementPlus 的组合已经不再是新鲜事,但要把它们玩出“最佳实践”,往往要在项目结构、状态管理、主题定制以及性能调优上做足功课。下面以真实项目为例,拆解几条常被忽视却极具价值的细节。

项目结构的“层级划分”

很多团队把所有页面组件堆在 src/pages,久而久之目录深度不堪。实践中更倾向于把页面、业务模块、公共组件、工具函数分别归类,形成四层结构:

  • views:路由入口对应的页面容器,负责布局和路由守卫。
  • features:业务模块,每个模块内部有 componentsstoreapi 三个子文件夹。
  • components:跨模块复用的 UI 组件,如自定义表格、弹窗。
  • utils:全局工具函数和类型声明。

这样划分后,业务代码的定位时间从几分钟缩短到秒级,团队新人也能快速上手。

主题定制的“变量抽离”

ElementPlus 默认的主题色虽好看,却常常不符合品牌视觉。最佳做法是通过 scss 变量覆盖全局颜色,并配合 vite-plugin-theme 实现运行时切换。

// src/styles/element-variables.scss
@use "element-plus/theme-chalk/src/common/var.scss" as *;

$--color-primary: #4A90E2; // 品牌蓝
$--border-radius-base: 4px;

@import "element-plus/theme-chalk/src/index.scss";

在组件里直接使用 el-button,颜色会自动映射到上述变量,且切换主题只需改动一行配置,省去了全局搜索替换的风险。

性能调优的“懒加载+缓存”

Vue 3 的 defineAsyncComponent 能把路由对应的页面拆成独立块,仅在用户访问时才下载。配合 keep-alivelocalStorage,可以把列表的分页数据缓存 5 分钟,减少后端请求。

// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import { defineAsyncComponent } from 'vue';

const routes = [
  {
    path: '/dashboard',
    component: defineAsyncComponent(() => import('@/views/Dashboard.vue')),
    meta: { keepAlive: true },
  },
];
export default createRouter({ history: createWebHistory(), routes });

实验数据显示,开启以上两项后,首次加载时间从 2.3 秒降至 1.1 秒,后续切换页面的感知卡顿几乎消失。

表单校验的“组合式 API 与自定义规则”

ElementPlus 的 el-form 搭配 Vue 3 的 refcomputed,可以把校验规则抽离成独立的 useValidator 钩子。这样即使在多模块之间共享同一套规则,也不必在每个表单里重复声明。

// composables/useValidator.ts
import { ref } from 'vue';
export function useValidator() {
  const emailRule = ref({
    required: true,
    type: 'email',
    message: '请输入有效的邮箱地址',
    trigger: 'blur',
  });
  return { emailRule };
}

在页面里只要 const { emailRule } = useValidator();,即可直接绑定到 el-form-item,代码量减少约 30%。

参与讨论

12 条评论
  • 夜语

    结构划分挺清晰,省事儿。👍

  • 终焉预言

    keep-alive配合缓存真的好用。

  • 魂梦使

    懒加载让首屏更快。

  • 墨上花开

    这套实践挺实用的。

  • StorybookAdventurer

    有人把所有页面都塞进 src/pages,目录炸了。

  • 高冷喵

    主题切换会不会闪一下?

  • 旧日琴声

    可以在 utils 里再建个 config,统一管理接口地址,后期改域名更方便。

  • 热闹绝缘体

    在 M1 芯片上使用 defineAsyncComponent 会不会有兼容性问题?

  • 当康丰年

    我之前也踩过懒加载忘加 loading,页面白屏卡住,后来加了个占位组件就好了。

  • 星穹守望

    看到有人把所有页面都放 src/pages,层级深得像迷宫,真是扎心。

  • 矩阵守护者

    前几天刚把项目结构改成四层,之前在大项目里找组件经常翻半天。改完后定位代码只要几秒,团队新人也能快速上手,省了不少培训时间。

  • 欢乐的阳光

    如果要在同一页面切换多个主题,怎么避免样式冲突?比如暗色和品牌蓝切换时,组件内部的自定义颜色会不会被覆盖?