jh-element

JH_Element —— 基于 Vite5 + Vue3 + TypeScript 的 ElementPlus 二次封装业务组件库
178
Install
npm install jh-element
Latest Version:0.1.0
Vue:3
License:MIT
Last Updated:Sep 18, 2026
Links: npm
Maintainer: zhanghang_lan

JH_Element

基于 Vite5 + Vue3 + TypeScript 的 ElementPlus 二次封装业务组件库 统一全局 UI 风格,支持一键换肤、按需/全量引入,自带预览 Demo 工作台。

特性

  • 🎨 主题系统:SCSS 变量 + 覆盖 ElementPlus 原生 Sass 变量,改一处全局生效
  • 🧩 业务组件:JhButton / JhTable / JhForm / JhDialog 带业务预设,只预设默认样式与默认参数
  • 📐 规范对齐(JH Design System):组件视觉逐批对齐公司的 jh-spec 规范,色值与尺寸全部取自 jh-spec/assets/tokens.css,收敛为 src/jh-element/styles/variables.scss 里的 $jh-table-* / $jh-btn-* / $jh-tag-* / $jh-badge-* / $jh-alert-* / $jh-tooltip-* 变量
    • 已对齐:Table(36px 浅蓝表头 + 装饰条、40px 行高、四种变体、圆形分页)、Button(30/24/42px 高度、实底 / 幽灵 / 文字三类)、Tag(light / dark / 普通标签)、Badge(16px 高、危险红)、Alert(10% 语义色底 + 30% 边框)、Tooltip(#181818 浮层)
    • 后续按组件批量继续推进(表单类、导航类、反馈类其余组件)
  • 📦 全量封装:按 ElementPlus 官网总览的分类,封装官方全部真实组件(共 104 个,含子组件),统一 Jh* 前缀
  • 🔁 完整透传:v-bind="$attrs" + 插槽透传,保留 el-* 组件的全部原生能力
  • 🧱 样式隔离:scoped + ::v-deep,全局变量与组件局部样式互不污染
  • ⚡ 按需引入:unplugin-auto-import + unplugin-vue-components(sass 模式)
  • 🖥 Demo 工作台:npm run dev 进入组件总览页,左侧树严格对齐 ElementPlus 官网总览(7 分类 + 82 条目,子组件折叠在所属条目下),右侧为「样式 / 属性 / 插槽 / 事件」四段文档

目录结构

jh-element
├─ src
│  ├─ jh-element                 # 组件库核心源码
│  │  ├─ components              # 组件源码(目录按 ElementPlus 官网总览分类)
│  │  │  ├─ basic                # 基础组件:JhButton(手写) / JhIcon / JhRow / JhCol / JhSpace …
│  │  │  │  └─ JhButton
│  │  │  │     ├─ JhButton.vue   # 手写实现(带业务预设)
│  │  │  │     └─ index.ts
│  │  │  ├─ config               # 配置组件:JhConfigProvider
│  │  │  ├─ form                 # 表单组件:JhForm(手写) / JhInput / JhSelect / JhOption / JhDatePicker …
│  │  │  ├─ data                 # 数据展示:JhTable(手写,另含 types.ts) / JhTableColumn / JhTree / JhTag …
│  │  │  ├─ navigation           # 导航:JhMenu / JhTabs / JhSteps / JhBreadcrumb …
│  │  │  ├─ feedback             # 反馈组件:JhDialog(手写) / JhDrawer / JhTooltip …
│  │  │  ├─ others               # 其他:JhDivider / JhWatermark
│  │  │  └─ index.ts             # 组件统一导出(按分类分组)
│  │  ├─ styles
│  │  │  ├─ variables.scss              # JH 自定义变量(主色/圆角/间距/字号)
│  │  │  ├─ element-vars-override.scss  # 覆盖 ElementPlus 原生 Sass 变量【换肤核心】
│  │  │  └─ index.scss                  # 组件库样式总入口
│  │  └─ index.ts               # 库安装入口,支持 app.use(JHElement)
│  ├─ demo
│  │  ├─ App.vue                # 组件总览工作台(左树 + 右侧条目卡片 / 组件文档)
│  │  ├─ DocTable.vue           # 文档表格(属性 / 插槽 / 事件区块统一展示)
│  │  ├─ BorderEditor.vue       # 边框基础样式编辑器(「Border 边框」条目使用)
│  │  ├─ ColorEditor.vue        # 色彩基础样式编辑器(「Color 色彩」条目使用)
│  │  ├─ TypographyEditor.vue   # 排版基础样式编辑器(「Typography 排版」条目使用)
│  │  ├─ ShadowEditor.vue       # 阴影基础样式编辑器(「Shadow 阴影」条目使用)
│  │  ├─ SpacingEditor.vue      # 间距基础样式编辑器(「Spacing 间距」条目使用)
│  │  ├─ TransitionEditor.vue   # 动效基础样式编辑器(「Transition 动效」条目使用)
│  │  ├─ ButtonEditor.vue       # 按钮基础样式编辑器(可调 --jh-btn-* 变量;入口在 JhButton 组件页的「按钮样式调整」区块)
│  │  ├─ VariablesViewer.vue    # 主题变量文件查看器(「Variables 变量文件」条目使用,只读展示 variables.scss 全文)
│  │  ├─ theme-save.ts          # 主题样式保存 / 读取 CSS 变量 / 混色等公共方法
│  │  ├─ component-meta.ts      # 总览元数据:官网 82 条目、组件清单、业务预设表
│  │  └─ api-data.ts            # 官方文档 API 数据(自动抓取生成,见下方说明)
│  ├─ main.ts                   # 开发入口,加载 demo 预览
│  └─ vite-env.d.ts
├─ index.html
├─ vite.config.ts
├─ tsconfig.json
├─ package.json
├─ .npmrc
└─ README.md

快速开始

# 1. 安装依赖
npm install

# 2. 启动本地 Demo 预览
npm run dev

# 3. 打包组件库(产物在 dist/)
npm run build

在业务项目中使用

npm install jh-element

依赖说明

  • vue(>= 3.4)由宿主工程提供(peerDependency),不随本包安装;
  • element-plus 与 @element-plus/icons-vue 随本包自动安装,无需手动再装;
  • 组件按 ElementPlus 官方「Sass 按需引入」方式引用组件样式,宿主工程需具备编译 Sass 的能力:npm i -D sass;
  • 主题样式在入口引一次即可:import "jh-element/style.css"。

方式一:全量注册

// main.ts
import { createApp } from "vue";
import JHElement from "jh-element";
import "jh-element/style.css";

createApp(App).use(JHElement).mount("#app");
<template>
  <jh-button type="primary" @click="handleSave">保存</jh-button>
</template>

方式二:按需引入

<script setup lang="ts">
import { JhButton, JhTable } from "jh-element";
import type { JhTableColumnConfig } from "jh-element";
// 按需引入时仍需引入一次组件库样式
import "jh-element/style.css";

const columns: JhTableColumnConfig[] = [
  { prop: "fileName", label: "病历名称" },
  { label: "操作", slot: "action" },
];
</script>

<template>
  <jh-button>保存</jh-button>
  <jh-table
    :data="list"
    :columns="columns"
    v-model:page="page"
    v-model:pageSize="size"
    :total="total"
  >
    <template #action="{ row }">
      <jh-button size="small" @click="handleEdit(row)">编辑</jh-button>
    </template>
  </jh-table>
</template>

主题修改

方式一:全局变量修改(推荐)

① 调整 JH 自身变量:编辑 src/jh-element/styles/variables.scss

$jh-color-primary: #2f6bff; // 改这里,主色全局生效
$jh-radius-base: 6px;
$jh-space-md: 16px;

// 表格(对齐 JH Design System,值取自 jh-spec/assets/tokens.css)
$jh-table-header-height: 36px; // 表头高度(紧凑 34px)
$jh-table-row-height: 40px; // 数据行高度(紧凑 36px)
$jh-table-header-bg: #e3ebff; // 表头背景 --jh-bg-table-header
$jh-table-header-color: #2f419b; // 表头文字 --jh-text-table-header
$jh-table-row-hover: #e5f8f7; // 行 hover --jh-table-row-hover
$jh-table-interactive: #13c0b3; // 交互色(选中行竖条 / 分页激活)

② 覆盖 ElementPlus 原生变量:编辑 src/jh-element/styles/element-vars-override.scss

@forward "element-plus/theme-chalk/src/common/var.scss" with (
  $colors: (
    "primary": (
      "base": $jh-color-primary,
    ),
  ),
  $border-radius: (
    "base": $jh-radius-base,
  )
);

该文件已通过 vite.config.ts 的 css.preprocessorOptions.scss.additionalData 注入到所有 scss 编译入口, 因此这里「改一处」,全部 el-* 组件与 JH 组件同步生效,无需逐个组件修改。

③ 运行时覆盖(CSS 变量):styles/css-variables.scss 把主题 token 输出为 CSS 自定义属性, 宿主可直接覆盖,做到「不重新构建即可换肤 / 局部定制」。样式分三层:

层级 位置 说明
① 全局变量 :root { --jh-* } 全量主题 token,由 variables.scss 生成
② ElementPlus 变量映射 :root { --el-*: var(--jh-*) } 让原生 el-* 组件跟随主题
③ 组件级变量 在组件样式内消费 如 JhTable 的 --jh-table-*,可在任意祖先节点覆盖

组件样式的写法约定:var(--jh-xxx, #{$jh-xxx}),第二个参数是级联回退值(Sass 编译结果), 变量未定义时自动使用,因此 Sass 始终是唯一数据源。

// 全局换肤:所有消费该变量的组件一起变
document.documentElement.style.setProperty("--jh-color-primary", "#25419b");
// 局部定制:只影响 .my-page 子树内的表格
document
  .querySelector(".my-page")
  .style.setProperty("--jh-table-header-bg", "#f7f7f7");
// 恢复默认:移除后自动回退到 Sass 编译值
document.documentElement.style.removeProperty("--jh-color-primary");

注意:ElementPlus 的派生色阶(--el-color-primary-light-3 等)是编译期算出的常量, 运行时改 --jh-* 不会重算它们;需要完整换肤时改 variables.scss 后重新构建。

方式二:单个组件样式微调

在每个组件内部的 <style scoped lang="scss"> 中,用 ::v-deep(scoped 下的深度选择器)修改内部 el 子组件, 只影响当前组件,不影响其他地方的 el-* 组件:

<style scoped lang="scss">
@use "../../../styles/variables.scss" as *;

.jh-button {
  border-radius: $jh-radius-base;

  // 仅作用于 JhButton 内部的 el 元素
  :deep(.el-icon) {
    transition: $jh-transition-base;
  }
}
</style>

组件说明

一、带业务预设的手写组件

组件 封装对象 预设能力 关键扩展
JhButton el-button 默认类型、圆角、hover 动效 block 占满整行
JhTable el-table + el-pagination 表头背景、行 hover、斑马纹、圆角边框、内置分页 columns 快捷列、v-model:page / v-model:pageSize / page-change
JhForm el-form 统一 label 宽度、表单间距、校验提示样式 validate / resetFields / clearValidate
JhDialog el-dialog 默认宽度 600px、拖拽、头部标题样式、底部按钮栏 confirm-text / cancel-text / confirm-loading / confirm / cancel

二、其余组件(纯透传包装)

除上表 4 个组件外,其余 101 个组件(覆盖 ElementPlus 官网总览的全部真实组件,含 JhOption / JhFormItem / JhTableColumn / JhTabPane 等子组件)均为纯透传包装:

  • 不预设任何默认属性,原生属性与事件通过 v-bind="$attrs" 完整透传
  • 插槽循环透传,保留 el-* 的全部原生插槽
  • 仅额外增加 jh-xxx 类名(如 JhInput → .jh-input),便于业务侧统一做全局样式定位
  • 因此属性、事件、插槽与对应的 el-* 完全一致,用法直接参考 Element Plus 官方文档即可

其中带必填属性的组件(JhTableV2 / JhOption / JhSelectV2 / JhMenuItem / JhSubMenu)会显式声明并转发这些必填属性,以保留类型提示。

全部组件均使用 defineOptions({ inheritAttrs: false }) + 模板内 v-bind="$attrs", 并循环透传全部插槽,因此 el-* 原生属性、事件、插槽全部可用。

已知限制:少数 Element Plus 组件会按「子组件名 / 实例链」识别子节点,纯透传包装会改变这些内部判定,处理方式如下:

  • JhDescriptions 的子项必须使用 el-descriptions-item(EP 按组件名过滤子节点,包装后会被忽略,故不提供 JhDescriptionsItem)
  • JhTour 的步骤必须直接使用 el-tour-step(EP 的 ElTourSteps 同样按 ElTourStep 组件名收集步骤,且包装层在首次渲染时尚未挂载、无法被回溯识别,故不提供 JhTourStep)
  • JhContainer 已在内部按相同口径补齐 direction 推断,正常使用 JhHeader / JhFooter 即可
  • 个别仅在极端场景生效的内部细节(如 JhCarousel 恰好两个子项时的补位逻辑、JhTableColumn 的多层表头嵌套)可能与原生有差异,遇到时直接改用对应的 el-* 组件

新增组件开发流程

以新增 JhTag(属于 data 分类)为例:

  1. 创建目录:src/jh-element/components/data/JhTag/
    JhTag/
    ├─ JhTag.vue     # 组件实现(<script setup lang="ts">)
    └─ index.ts      # export { default as JhTag } from "./JhTag.vue";
    
  2. 编写组件:遵循统一规则
    • 纯透传包装(绝大多数组件):模板只写 <el-xxx v-bind="$attrs" class="jh-xxx"> + 插槽循环透传,脚本里仅保留 useSlots 取插槽名,无需声明 props
    • 需要业务预设时(如 JhButton / JhTable)再声明 interface JhXxxProps(写全注释)并显式绑定默认值
    • defineOptions({ name: "JhTag", inheritAttrs: false })
    • 需要暴露给父组件的方法通过 defineExpose 暴露
  3. 样式微调(可选):纯透传组件可不写 <style>;需要时用 <style scoped lang="scss">,@use "../../../styles/variables.scss" as *;,用 :deep() 调整 el 子组件
  4. 导出组件:在 src/jh-element/components/index.ts 对应分类下追加
    export * from "./data/JhTag";
    

    components/index.ts 是统一出口,jh-element/index.ts 会自动全量注册,无需其他改动。

  5. 补充总览页:
    • 在 src/demo/component-meta.ts 对应分类的条目数组里补一行 ["JhTag", "标签", "el-tag", "一句话描述"]
    • 若该组件有专属样式示例,再在 src/demo/App.vue 的 doc-section 内按组件 id 补充示例区块
  6. 验证:npm run dev 查看效果,npm run type-check + npm run build 确认通过

说明

  • 项目同时兼顾「本地 Demo 预览」与「组件库导出」:npm run dev 加载 src/main.ts → src/demo/App.vue;npm run build 仅打包 src/jh-element,产物为 ESM 格式(dist/jh-element.js + dist/style.css),并在 dist/types 输出类型声明。
  • 总览工作台(npm run dev):
    • 左侧树严格对齐官网总览:7 个分类 + 官方 82 个条目(含 Border / Color / Typography 等样式文档页,以及 Loading / Message 等指令、服务条目),条目下折叠我们封装的组件(子组件挂在所属父条目下);末尾额外挂一个自定义分类「主题样式 Theme」
    • 右侧为「样式 / 属性 / 插槽 / 事件」四段:手写组件展示专属示例,其余组件展示不传属性时的默认外观(需要必填数据、依赖父组件或默认不可见的组件给出说明与官方文档入口)
    • 属性 / 插槽 / 事件的表格数据来自 src/demo/api-data.ts,由官方文档各组件页的 API 表格自动抓取生成(仅 demo 使用,不参与组件库构建);手写组件的业务预设表单独维护在 component-meta.ts 的 presetTables
    • 右侧内容区带锚点导航(对齐 jh-spec/patterns/anchor-detail-pattern.md 形态 A:右侧悬浮锚点 + scrollspy):自动收集当前页分节标题(一级为 样式 / 属性 / 插槽 / 事件 或分类,二级为示例与表格标题),点击平滑滚动定位、滚动时反向高亮当前分节;切换组件后自动重建并回到顶部
    • 主题样式条目的可视化编辑器:3 个库内主题维度 + 1 个变量文件只读条目(共 4 个条目),右侧提供同款「调整 → 实时预览 → 保存为基础样式」编辑器
      • Border 边框(Basic 分类):边框宽度 / 线型 / 颜色 / 圆角(支持分边、分角),保存后可直接用 class="jh-border"
      • Color 色彩(Basic 分类):五个语义色 + 文本 / 次级文本 / 边框 / 容器背景 / 悬浮背景,并展示 ElementPlus 自动派生的 light-3 ~ light-9 / dark-2 色阶
      • Typography 排版(Basic 分类):小 / 基础 / 大字号档位、字体族(含预设)、基础行高
      • Shadow 阴影(主题样式 Theme):sm / base / lg 三档阴影的偏移、模糊与颜色
      • Spacing 间距(主题样式 Theme):xs / sm / md / lg 四档间距
      • Transition 动效(主题样式 Theme):过渡属性 / 时长 / 缓动函数(组合成 $jh-transition-base)
      • Variables 变量文件(主题样式 Theme):只读展示 src/jh-element/styles/variables.scss 当前全文(带行号、行数、已保存覆盖块计数与一键复制),文件变更后自动热更新
      • 前三个属于官网条目,放在「基础组件 Basic」下;后四个是库内主题维度,放在自建的「主题样式 Theme」分类下(标签显示「库内主题维度」且不提供官方文档入口)
      • Button 按钮的编辑器(ButtonEditor.vue 可调 --jh-btn-blue 等 18 个变量)不放在本分类下,入口固定在**「基础组件 Basic → Button 按钮 → JhButton 按钮」组件页「样式」分节的右列**(「按钮样式调整」面板,与左侧示例左右并排;窄屏自动上下堆叠),保存逻辑与 vite.config.ts 里的 button 保存分区对应
      • 保存通过 dev 接口写入 src/jh-element/styles/variables.scss 末尾的分区覆盖块(带 // >>> jh-theme:<分区> 标记,重复保存为原地替换),接口由 vite.config.ts 的 jhThemeWriter 插件提供,仅 npm run dev 生效;写入前对数值 / 颜色 / 线型 / 字体族 / 过渡属性 / 缓动函数做白名单校验,非法值直接返回 400
  • vue、element-plus、@element-plus/icons-vue 在打包时被外部化,由宿主工程提供,避免重复打包。
  • 各包装组件内部的 el-* 使用由 unplugin-vue-components 的 ElementPlusResolver(sass 模式)自动注入对应组件样式;构建产物中这些样式入口按 element-plus/es 规则保持外部化(element-plus/es/components/<name>/style/index), 即宿主工程需按 ElementPlus 的标准方式提供组件样式;组件库自身的样式统一输出在 jh-element/style.css。
  • 组件库导出的类型中,JhTable 的快捷列配置类型为 JhTableColumnConfig;与之对应的组件是 JhTableColumn(封装 el-table-column)。

Related Packages

@yymojo-tec/mojo-ui

Mojo UI 是 YYmojo 旗下维护的 UI 组件库。

9,973
@npm_qy/y-ui

Y-Ui component library: business components composed on element-plus

347
@mindvalley/eve-ai-ui

Eve AI - Component Library

14,409
@apform-ui/core

Apform UI:Element Plus 底座包装在本库栈下;el-* 算可用能力,视觉以本库 Design T...

8,379 0
yo-pc-ui-component

Vue 3 Component Library based on Element Plus with custom styles and logic

1,211

Version History

Version Released Vue License
0.1.0 ^3.4.0 MIT