三月七组件库设计
三月七组件库设计
三月七组件库目前有两种实现:
@mar7th/march7th-ui:基于原生 Web Components。@mar7th/march7th-ui-vue:面向 Vue 3 项目。
维护两种实现不是为了重复造两套轮子,也不是简单地让 Vue 组件包裹一层 Custom Element。两者面向的使用场景不同,但共享同一套主题、组件命名和交互语义。
设计目的
让不同网站共享基础控件
博客、作品展示站、图集浏览站、游戏论坛和网页游戏入口的业务不同,但按钮、表单、弹窗、提示、分页、标签页和内容卡片会反复出现。
如果每个项目重新实现这些控件,视觉和行为一定会逐渐分叉。组件库要解决的是跨项目重复,而不是绑定某一种网站结构。
让组件脱离单一框架
只做 Vue 组件库时,组件无法自然地进入纯 HTML、Astro 静态内容或其它框架。
原生 Web Components 提供了最低公共层:浏览器认识自定义元素,Astro、Vue、React、Svelte 和传统页面都可以直接使用。对于只需要少量交互的页面,不必为了一个按钮或提示框挂载完整框架。
保留 Vue 的开发体验
原生组件适合跨框架,但 Vue 项目仍然需要 v-model、Composition API、类型提示、composable 和 Tree-shaking。
因此 Vue 版保留独立实现,使用 Vue 3.5 和 TypeScript 提供更符合 Vue 习惯的 API。两套组件库共享设计系统,但不强迫其中一方迁就另一方的运行模型。
总体方案
主题包负责颜色、状态色、圆角、阴影和模式切换;原生版与 Vue 版分别负责各自运行环境中的组件结构、状态和交互。
原生版:跨框架公共层
@mar7th/march7th-ui 使用 Custom Elements、Shadow DOM 或标准 DOM 事件构建组件,不依赖 Vue、React 等 UI 框架。
为什么选择 Web Components
Web Components 的价值不是“原生一定更轻”,而是它提供了稳定的浏览器级组件协议:
- 标签可以直接写进 HTML 和 Astro 模板。
- 属性可以作为静态内容输出。
- 事件可以被任何框架监听。
- 自定义元素注册后,已有标签会自动升级。
- 可以通过 npm、CDN 或自托管文件使用。
这使原生版特别适合 Markdown、MDX 和国际化 HTML。
例如不同语言的词条可以拥有完全不同的 DOM 结构,并直接包含组件:
<m7-alert> <m7-alert-title>操作完成</m7-alert-title> <m7-alert-description>文件已经保存。</m7-alert-description></m7-alert>
<m7-button type="primary" href="/next/">继续</m7-button>页面不需要因为这一段内容引入 Vue,也不需要把翻译拆成大量占位符再由组件重新组合。
双重使用方式
原生版同时提供:
m7-*Web Components,用于完整交互和状态管理。- CSS 类与 Token,用于不需要自定义元素生命周期的静态结构。
这让项目可以根据页面复杂度选择使用方式,而不是所有元素都必须升级成组件。
完整包与按需构建
全量包适合快速体验,也支持通过 CDN 直接加载:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mar7th/march7th-ui@1.2.0/dist/march7th-theme.css"><script src="https://cdn.jsdelivr.net/npm/@mar7th/march7th-ui@1.2.0/dist/march7th-ui.standalone.min.js"></script>但多数项目不会使用全部组件。原生版提供 Builder,可以勾选需要的组件并生成精简 JS 和 CSS;也可以手动按需加载单个组件文件。
这个方案在“安装即用”和“控制最终体积”之间保留了选择。
Vue 版:Vue 项目的完整体验
@mar7th/march7th-ui-vue 使用 Vue 3 Composition API 和 TypeScript,适合完整 Vue 应用以及 Astro 中的 Vue Island。
<script setup lang="ts">import { ref } from "vue"import { M7Button, M7Input,} from "@mar7th/march7th-ui-vue"import "@mar7th/march7th-ui-vue/style.css"
const value = ref("")</script>
<template> <M7Input v-model="value" placeholder="请输入内容" /> <M7Button>保存</M7Button></template>Vue 版提供:
- Vue 3.5+ 组件。
- TypeScript 组件和 composable 类型。
v-model等 Vue 原生交互方式。- 按需导入和 Tree-shaking。
useToast、useFocusTrap等组合式能力。- 响应式布局 Token 和完整主题样式。
两套实现如何保持一致
共享主题,而不是复制颜色
原生版已经正式依赖 @mar7th/march7th-theme,Vue 版也使用相同的 OKLCH 主题变量和兼容映射。
主题模式、动态 Hue、状态色和本地存储状态都来自同一主题系统。Astro 页面中的原生组件和 Vue Island 因此可以同时响应一次主题切换。
对齐命名和语义
两套实现尽量保持组件名称、状态名称和使用目的对应:
| 原生版 | Vue 版 | 用途 |
|---|---|---|
m7-button | M7Button | 按钮与链接操作 |
m7-input | M7Input | 文本输入 |
m7-modal | M7Modal | 模态对话框 |
m7-toast | M7Toast / useToast | 轻提示 |
m7-lightbox | M7Lightbox | 图片查看 |
m7-theme-switch | M7ThemeSwitch | 主题切换 |
内部实现可以不同,但用户看到的视觉、状态反馈和交互目的应该一致。
允许同一页面混用
Astro 项目可以让大部分内容保持静态,只在复杂交互区域使用 Vue:
---import VueEditor from "@/components/VueEditor.vue"import "@mar7th/march7th-ui-vue/style.css"import "@mar7th/march7th-ui/theme.css"---
<m7-alert>由原生组件处理的静态提示</m7-alert><VueEditor client:visible />两种组件不需要互相控制,只需要继承相同主题状态。
当前成果
原生版
@mar7th/march7th-ui 当前发布版本为 1.2.0:
- 已完成 58 个组件。
- 覆盖表单、数据展示、反馈导航、交互、内容和工具等七类能力。
- 支持 npm、CDN、完整包、单文件按需加载和 Builder 定制构建。
- 已将
@mar7th/march7th-theme作为正式依赖。 - 可以在 Astro、Vue、React、Svelte 和普通 HTML 页面使用。
Vue 版
@mar7th/march7th-ui-vue 当前版本为 0.1.0:
- 已完成 46+ 个 Vue 组件。
- 支持 Vue 3.5+、TypeScript 和按需导入。
- 提供主题切换、动态 Hue、响应式 Token 和常用 composable。
- 可以直接用于 Vue 应用,也可以作为 Astro Vue Island 使用。
已完成的整合验证
- 原生版和 Vue 版可以在同一个 Astro 页面中同时运行。
- 两者可以共享同一个主题模式、Hue 和状态色色阶。
- 原生组件可以直接写进 Markdown、MDX 和可信 i18next HTML 词条。
- Astro 静态页面不需要因为少量组件整体 hydration。
- 原生版继续保留 CDN 直连能力,适合无构建项目和旧项目渐进接入。
边界与后续
组件库只解决可复用的基础控件和通用内容组件,不应该把博客、论坛或作品站的完整业务页面塞进组件包。
复杂数据流、业务权限和页面布局仍由具体项目负责。组件库提供稳定的按钮、输入、提示和交互积木,主题包提供统一视觉,Astro 模板负责把内容、路由和可选 Feature 组合成网站。
下一步更重要的不是继续追求组件数量,而是逐步加强两套实现的 API 对照、可访问性测试、按需产物和文档,让“同一种能力在不同框架中怎么使用”变得更加明确。
March7th