Skip to content

MapGIS/MapGIS-WebClient-Vue3

Repository files navigation

基于 Vue 3 + Vite + TypeScript 的组件库。

一、特性

  • 开箱即用的高质量 Vue 3组件
  • 丰富的文档和示例
  • 采用流行的技术栈

二、深入了解

2.1 代码结构

├── .husky                          // git辅助工具
├── .vscode                         // 工作区配置目录
├── scripts                         // 脚本资源
├── templates                       // 组件模板
├── packages                        // 组件库目录
│   ├── ui                          // ui组件库
│       ├── components              // 组件库源码
│           ├── package.json        // 项目清单文件(不发布)
│       ├── docs                    // VitePress API文档
│           ├── package.json        // 项目清单文件(不发布)
│       ├── entrance                // 组件库入口
│           ├── package.json        // 项目清单文件(发布)
│       ├── examples                // 示例程序
│           ├── package.json        // 项目清单文件(不发布)
│       ├── hooks                   // 可复用的功能
│           ├── package.json        // 项目清单文件(不发布)
│       ├── storybook               // 组件故事书
│           ├── package.json        // 项目清单文件(不发布)
│       ├── utils                   // 工具包
│           ├── package.json        // 项目清单文件(不发布)
│       ├── deploy.bat              // 组件库资源部署脚本
│       ├── publish.bat             // 组件库发布脚本
│   ├── common                      // common组件库
│       ├── ...                     // 同ui库
│   ├── leaflet                     // leaflet组件库
│       ├── ...                     // 同ui库
│   ├── mapboxgl                    // mapboxgl组件库
│       ├── ...                     // 同ui库
│   ├── cesium                      // cesium组件库
│       ├── ...                     // 同ui库
├── package.json                    // 项目清单文件(不发布)
├── pnpm-workspace.yaml             // pnpm工作空间文件
  • 可以看到在一个组件库包中,只有entrance包是被允许发布的,其他包都是禁止发布的
  • 组件工具包可以被其他组件库共用
  • 组件示例程序引用的是组件库源码包,支持组件开发调试
  • 组件文档引用的是组件库源码包,支持组件开发调试
  • 组件故事引用的是entrance包打包后的组件库,支持生产环境下测试

2.2 环境准备

本项目是一个基于pnpm的单体多包仓库,只支持pnpm包管理器,请先确保是否已经安装pnpm

Node.js版本要求18以上

# npm安装pnpm
npm i -g pnpm

# yarn安装pnpm
yarn global add pnpm

2.3 开发

# 安装
pnpm install

# 运行组件库ui项目示例
pnpm ui:serve

# 打包组件库ui
pnpm ui:build

# 运行组件库ui地图故事
pnpm ui:storybook

# 运行组件库ui文档
pnpm ui:docs:dev

2.4 内置命令

以ui组件库为例:

# 创建组件
pnpm cc

# 通过git交互式提交代码,建议通过此命名进行提交
pnpm commit

# ui组件发布到公共仓库npmmjs
ui:publish

# ui组件库发布到私有仓库11.130
ui:publish:private

# ui组件库资源部署
ui:deploy

# ui组件库示例项目运行,同ui:server
ui:dev

# ui组件库示例项目运行
ui:serve

# ui组件库示例项目打包
ui:examples:build

# ui组件库示例项目打包预览
ui:examples:preview

# ui组件库示例项目仅预览,需先前已打过包
ui:examples:preview-only

# ui组件库打包
ui:build

# ui组件库单元测试
ui:test

# ui组件库覆盖率测试
ui:test:coverage

# ui组件库故事运行,会先进行组件库打包
ui:storybook

# ui组件库故事仅运行,需先前已打过包
ui:storybook-only

# ui组件库故事打包,会先进行组件库打包
ui:storybook:build

# ui组件库故事仅打包
ui:storybook:build-only

# ui组件库故事预览,会先进行故事打包
ui:storybook:preview

# ui组件库故事仅预览,需先前已打过包
ui:storybook:preview-only

# ui组件库文档运行
ui:docs:dev

# ui组件库文档打包
ui:docs:build

# ui组件库文档预览,会进行文档打包
ui:docs:preview

# ui组件库文档仅预览,需先前已打过包
ui:docs:preview-only

# 格式化文档
prettier

# 进行TypeScript类型检查,分析类型错误
type-check

# 代码质量检查,是否符合ESLINT规则
lint

# 检查并修复错误
lint:fix

# 安装前钩子
preinstall

# 修改记录生成
changelog

三、技术栈

类别 技术 说明
核心框架与语言 Vue3 作为基础框架,提供响应式系统和组件化开发能力
TypeScript 用于增强类型安全,提升代码可维护性
构建和工具链 Vite 主流构建工具,提供快速的冷启动和热更新
pnpm 作为高效的包管理工具,用于依赖管理和Monorepo架构,通过物理存储优化解决资源浪费问题,通过依赖隔离机制保障代码安全,通过原生Workspace支持提升协作效率
测试和质量保障 Vitest 基于Vite的单元测试框架
ESLint/Prettier 代码规范和格式化工具,确保代码风格统一
Husky 用于在Git钩子中集成代码质量检查和自动化格式化任务,确保每次提交的代码都符合规范
Commitlint 标准化提交规范框架:提供Git提交标准化框架,通过适配器扩展交互逻辑,需搭配适配器使用
pretty-quick 与Husky搭配在提交代码前自动格式化更改的文件,按需触发Prettier,仅处理Git变更文件并集成到开发流程
czg 交互式命令行工具,用于生成标准化的Git提交信息,以符合Commitlint等规范,Commitizen CLI替代品,内置cz-git适配器的独立工具,优化启动速度和工程化体验
状态管理与路由 Pinia 替代Vuex的轻量级状态管理库
Vue Router 处理前端路由,常用于复杂单页应用
UI组件库与设计 Ant Design Vue 4.x 适用于企业级中后台项目
LESS CSS预处理工具,支持变量、嵌套、混合等特性
CSS变量 实现运行时主题切换
BEM Block Element Modifier,块元素修饰符命名方法,代码不仅更具结构性,而且也更易于理解每个部分的关系和作用。这有助于团队协作开发,减少样式冲突,并提高代码的整体质量
文档与示例 VitePress 基于Vite的新一代静态网站生成器
Example展示页面 提供实际组件使用的例子
Storybook 用于组件展示和测试
辅助工具与扩展库 Handlebars JavaScript 的页面模板库
架构 Monorepo 采用pnpm workspace管理多包组件库,统一仓库管理,共享依赖与构建流程

四、组件规范(最佳实践)

高效、复用!!!

  • 能自动化的就不要手动
  • 能复用的就不要重复编写

4.1 单个组件文件含义

以xxx组件为例:

├── __tests                         // 组件的测试文件夹,存放组件的测试文件
│   ├── index.spec.tsx              // 测试文件,默认提供组件的CSS类测试,一般只有一个测试文件
├── examples                        // 组件示例文件夹
│   ├── basic.vue                   // 基本用法示例,一个组件可以有多个示例文件,按用法命名,可以被引用到文档、故事中
├── stories                         // 组件故事
│   ├── xxx.stories.ts              // 组件故事文件,以kebab-case方式命名,一般只有一个故事文件
├── style                           // 组件样式文件夹
│   ├── index.less                  // 样式文件,符合LESS规范和BEM架构,可使用基于AntD的CSS变量,一般只有一个样式文件
├── xxx.vue                         // 组件文件,组合模板、逻辑和样式
├── index.ts                        // 组件入口文件,集中导出组件或功能,实现外部按需引入
├── instance.ts                     // 组件实例类型声明文件,当父组件通过ref引用子组件时,可约束该引用的类型
├── types.ts                        // 组件类型声明文件,定义组件Props、Emit等核心接口,确保类型一致性
├── use-xxx.ts                      // 组件业务逻辑文件,采用组合式函数写法,被xxx.vue使用,支持复用

文件名以kebab-case命名,组件名以PascalCase命名

4.2 组件的关联组件文件含义

关联组件表示功能强关联、高频同时使用,比如Button和ButtonGroup组件,这里以xxx的关联组件xxx-yyy组件为例:

  ├── __tests                       // 组件的测试文件夹
  │   ├── index.spec.tsx            // 测试文件,增加xxx-yyy组件的单元测试【必须】
  ├── examples                      // 组件示例文件夹
  │   ├── basic.vue                 // 基本用法示例,可增加xxx-yyy组件的组合示例【可选】
+ │   ├── xyz.vue                   // 关于xxx-yyy组件用法示例【可选】
  ├── stories                       // 组件故事
  │   ├── xxx.stories.ts            // 组件故事文件,增加xxx-yyy组件的故事【必须】
  ├── style                         // 组件样式文件夹
  │   ├── index.less                // 样式文件,增加xxx-yyy组件的样式定义【必须】
  ├── xxx.vue                       // 组件文件
+ ├── xxx-yyy.vue                   // xxx-yyy组件文件【必须】
  ├── index.ts                      // 组件入口文件,增加xxx-yyy的组件安装和导出【必须】
  ├── instance.ts                   // 组件实例类型声明文件,增加xxx-yyy组件的实例类型声明【必须】
  ├── types.ts                      // 组件类型声明文件,增加xxx-yyy的组件类型声明【必须】
  ├── use-xxx.ts                    // 组件业务逻辑文件
+ ├── use-xxx-yyy.ts                // 组件业务逻辑文件【必须】

4.2 多个组件的结构定义

以components组件包为例:

├── aaa                             // 组件aaa
├── bbb                             // 组件bbb
├── ccc                             // 组件目录ccc
│   ├── lll                         // 组件目录ccc下面的组件lll
│   ├── mmm                         // 组件目录ccc下面的组件mmm
├── ddd                             // 组件ddd
│   ├── ppp                         // 组件ddd的子组件ppp
│   ├── qqq                         // 组件ddd的子组件目录qqq
│       ├── uuu                     // 组件ddd的子组件目录qqq下面的组件uuu
│       ├── vvv                     // 组件ddd的子组件目录qqq下面的组件uuu
├── components.ts                   // 组件注册和导出,支持全量注册和按需注册
├── index.ts                        // 组件入口,组件导出,包括组件类型声明和组件业务逻辑
  • 支持平级式和内聚式组件结构,按功能的耦合度来选择不同的方,比如aaa和bbb就是平级式、ddd和ppp就是内聚式
  • 支持组件目录,可定义在父组件内部,对子组件进行分类
  • 所有的组件需在components.ts中形成组件列表进行注册并具名导出
  • 所有的组件需在index.ts中进行导出,包括组件自身的任何导出

建议:实际开发时,不要过深的层次结构,能散在根目录下的就不要归类到目录中,能在父组件下形成子组件列表的就要再进行分类

五、新增组件(组件结构和展示)

新增组件前需要对组件做好设计,包括组件名、在组件库中的结构、组件的属性、事件、组件的UI等

5.1 手动新增

以组件my-com为例:

  1. 复制aaa组件的源码到components目录下或某个组件分类或某个父组件下,这里我们假设放置到components的my-dir目录下

  2. 将含有aaa的文件修改为实际组件名的kebab-case形式my-com,涉及到以下文件:

    # 直接修改
    stories/aaa.stories.ts      -> stories/my-com.stories.ts
    aaa.vue                     -> my-com.vue
    use-aaa.ts                  -> use-my-com.vue
    
  3. 同步修改文件名变化引起的导入,涉及到以下文件:

    __tests__/index.spec.tsx
    my-com.vue
    index.ts
    instance.ts
    
  4. 修改组件名Aaa为新增组件的PascalCase形式MyCom,涉及到以下文件:

    __tests__/index.spec.tsx
    my-com.vue
    index.ts
    instance.ts
    
  5. 修改样式类aaa为my-com,涉及到以下文件:

    __tests__/index.spec.tsx
    style/index.less
    my-com.vue
    
  6. 统一修改其他Aaa为PascalCase形式MyCom

  7. 统一修改其他aaa为camelCase形式myCom

  8. 修改components/components.ts,添加组件引入、形成新的组件列表,并导出该组件

      ...
    
    + import MyCom from './my-com'
    
      const components: Plugin[] = [
      ...,
    + MyCom
      ]
    
      export {
      ...,
    + MyCom
      }
    
      ...
  9. 修改components/index.ts,导出组件

      ...
    + export * from './my-com'
      ...
  10. 添加组件文档

    组件文档项目基于VitePress编写,所有的组件文档都在组件库的docs项目内,其目录结构如下:

    ├── .vitepress                      // VitePress主题和配置目录
    │   ├── components                  // 组件配置
    │       ├── zh.json                 // 中文版组件列表配置
    │   ├── config                      // VitePress配置目录
    │       ├── en.mts                  // 英文版配置,包括导航条和侧边栏配置
    │       ├── index.mts               // 配置入口,集成其他配置
    │       ├── shared.mts              // 公共配置,与语言无关
    │       ├── zh.mts                  // 中文版配置,包括导航条和侧边栏配置
    │   ├── theme                       // VitePress主题目录,可在此目录内引入组件,配置主题和全局样式
    ├── api                             // 保留的组件英文版文档目录,内部结构与zh目录相同
    ├── examples                        // 保留的组件用法示例,目前用法示例均在组件内部,此处暂保留
    ├── public                          // 静态资源
    │   ├── images                      // 保留的图片静态资源,当文档中有图片需要展示时,可将图片放到此目录内
    ├── zh                              // 组件中文版文档目录
    │   ├── api                         // api文档目录
    │       ├── components              // 组件部分的文档,结构与组件结构一致
    │       ├── guide                   // 开发指南部分的文档,包括介绍、安装和快速上手
    │       ├── other                   // 其他部分的文档,包括更新日志和常见问题
    │       ├── index.md                // 首页内容
    ├── index.md                        // 英文版首页内容
    

    zh/api/components目录下按照新增组件的同结构创建以组件kebab-case命名的md文档,内容可复制于aaa.md,然后修改里面与组件名称、用法路径相关的内容

    这里按照前面的示例,我们需要创建文档zh/api/components/my-dir/my-com.md

    # MyCom
    
    介绍。
    
    > `<my-com></my-com>`
    
    ## 基本用法
    
    <preview path="../../../../../components/my-dir/my-com/examples/basic.vue"></preview>
    
    :::api
    
    ## API
    
    ### 属性
    
    | 参数 | 说明 | 类型 | 默认值 | 版本 |
    | ---- | ---- | ---- | ------ | ---- |
    
    ### 事件
    
    | 事件名称 | 说明 | 回调参数 | 版本 |
    | -------- | ---- | -------- | ---- |
    
    ### 方法
    
    | 名称 | 描述 | 版本 |
    | ---- | ---- | ---- |
    
    :::

    在左侧导航条中增加组件菜单,修改.vitepress/components/zh.json

    [
      {
        "text": "MyDir",
        "collapsed": false,
        "base": "/api/components/my-dir/",
        "items": [
          {
            "text": "MyCom",
            "link": "my-com"
          }
        ]
      }
    ]

⚠️⚠️⚠️ 请仔细检查每一处修改!!!务必遵守规范!!!

5.2 自动新增(推荐)

可以看到,每次新增组件就需要手动修改大量的地方,非常的繁琐,还容易遗忘和出错。

本项目提供了基于Handlebars引擎的组件模板,可通过命名pnpm cc交互式的进行组件创建,上面的N多步骤一键搞定!!!

交互式模式

pnpm cc

命令行参数模式(推荐用于 AI/脚本调用)

# 完整参数
pnpm cc --name MyComponent --module mapboxgl --dir map/overlay

# 简写形式
pnpm cc -n MyComponent -m mapboxgl -d map/overlay

参数说明:

参数 简写 说明 是否必填
--name -n 组件名称(PascalCase)
--module -m 目标模块(ui/common/mapboxgl/leaflet/cesium)
--dir -d 组件目录(kebab-case,多级用 / 分隔)

使用示例:

# 在 ui 包根目录创建组件
pnpm cc -n Button -m ui

# 在 mapboxgl 包的 map 目录下创建组件
pnpm cc -n WebMap -m mapboxgl -d map

# 在 cesium 包的多级目录创建组件
pnpm cc -n SceneControl -m cesium -d scene/control
PS E:\MapGIS-WebClient-Vue3> pnpm cc

> @mapgis/components-workspace@ cc E:\MapGIS-WebClient-Vue3
> node scripts/component-generator.js

? 组件名称(PascalCase): MyCom
? 组件模块(如ui等模块): ui
? 组件目录(相对组件模块components目录,默认为空): my-dir
✔ 生成: __tests__/index.spec.tsx
✔ 生成: E:\MapGIS-WebClient-Vue3\ui\docs\zh\api\components\my-dir/my-com.md
✔ 生成: examples/basic.vue
✔ 生成: stories/my-com.stories.ts
✔ 生成: style/index.less
✔ 生成: my-com.vue
✔ 生成: index.ts
✔ 生成: instance.ts
✔ 生成: types.ts
✔ 生成: use-my-com.ts
组件生成成功!路径: ui\components\my-dir\my-com
  • 组件名称:务必输入PascalCase形式的组件名称
  • 组件模块:默认是ui,可输入cesium、common、mapboxgl、leaflet等
  • 组件目录:相对组件模块components目录,默认为空,如果输入my-dir,则组件代码将放入到my-dir下面,如果需要增加地图组件的子组件,我们需要输入此目录,将代码放到地图组件的内部

components/components.tscomponents/index.ts的修改采用了占位符的方式,请千万要保持占位符的内容不变,否则组件创建命令会提示错误!!!

components/components.ts

// 🛑🛑🛑 AUTO_IMPORT_PLACEHOLDER - DO NOT DELETE OR MODIFY 🛑🛑🛑

const components: Plugin[] = [
  // 🛑🛑🛑 AUTO_COMPONENTS_PLACEHOLDER - DO NOT DELETE OR MODIFY 🛑🛑🛑
]

export {
  // 🛑🛑🛑 AUTO_EXPORT_PLACEHOLDER - DO NOT DELETE OR MODIFY 🛑🛑🛑
  // prettier-ignore
}

components/index.ts

// 🛑🛑🛑 AUTO_EXPORT_PLACEHOLDER - DO NOT DELETE OR MODIFY 🛑🛑🛑

5.3 新增组件初次测试

此时,我们仅仅是按照组件规范完成了组件代码的初步编写。

当我们执行pnpm ui:storybook的时候,已经可以在组件故事的左侧看到我们新增的组件故事了。

当我们执行pnpm ui:docs:dev的时候,也可以在组件文档的左侧看到我们新增的组件文档了。

以ui组件库为例,新增组件后,虽然组件故事和组件文档可以展示,但是当我们执行yarn ui:dev时不会有效果,因为示例项目中没有增加对该组件的示例

5.4 展示组件示例

组件库的examples是针对组件的示例项目,可以在此项目中增加示例的集成展示。

以ui组件为例:

需要修改examples/assets/components.json文件,增加对该示例的配置。

其他组件库的示例项目均需要按照自己项目的规范进行添加

  [
    {
      "id": "base",
      "name": "基础",
      "groups": [
        {
          "id": "Overview",
          "name": "概览"
        },
+       {
+         "id": "MyCom",
+         "name": "我的组件"
+       }
      ]
    }
  ]

ui组件库的示例项目,会根据配置的组件id和组件name,去自动按照组件id指向的组件名称去寻找组件基本用法示例,即组件结构内examples/basic.vue的内容

运行命令pnpm ui:dev可以看到新增的组件示例了,当我们修改组件结构内examples/basic.vue的内容时,示例效果也会跟随变化。

5.5 新增组件综合测试

至此,组件基本用法示例在示例项目、组件文档和组件故事中都可以展示了,可通过如下命令进行确认:

这里仍然以ui组件库为例:

# ui组件库示例项目运行,同ui:server
pnpm ui:dev

# ui组件库示例项目运行
pnpm ui:serve

# ui组件库示例项目打包
pnpm ui:examples:build

# ui组件库示例项目打包预览
pnpm ui:examples:preview

# ui组件库示例项目仅预览,需先前已打过包
pnpm ui:examples:preview-only

# ui组件库打包
pnpm ui:build

# ui组件库单元测试
pnpm ui:test

# ui组件库覆盖率测试
pnpm ui:test:coverage

# ui组件库故事运行,会先进行组件库打包
pnpm ui:storybook

# ui组件库故事仅运行,需先前已打过包
pnpm ui:storybook-only

# ui组件库故事打包,会先进行组件库打包
pnpm ui:storybook:build

# ui组件库故事仅打包
pnpm ui:storybook:build-only

# ui组件库故事预览,会先进行故事打包
pnpm ui:storybook:preview

# ui组件库故事仅预览,需先前已打过包
pnpm ui:storybook:preview-only

# ui组件库文档运行
pnpm ui:docs:dev

# ui组件库文档打包
pnpm ui:docs:build

# ui组件库文档预览,会进行文档打包
pnpm ui:docs:preview

# ui组件库文档仅预览,需先前已打过包
pnpm ui:docs:preview-only

六、组件开发(组件逻辑和文档示例)

进入到此部分,需要确保组件已经创建,并且创建的组件能够在示例项目、文档项目和故事项目中都得到正确的展示,如果还未完成,请参考第五部分进行完成,并且要确保组件已事先做好了设计,下面的部分是按照设计进行开发实现。

6.1 定义组件属性和事件

修改组件内部的types.ts文件,增加对外的属性和事件,并补充好注释内容,此内容需要同步到组件文档的API部分,请确保二者务必一致,以CollapseButton组件为例:

import { isBoolean } from '@mapgis/webclient-vue3-ui-utils'
import type { ExtractPropTypes } from 'vue'

export const collapseButtonProps = {
  /**
   * @description 折叠方向,位于被折叠区域的位置
   */
  direction: {
    type: String,
    validator(value) {
      return ['left', 'right', 'top', 'bottom'].includes(value)
    },
    default: 'right'
  },
  /**
   * @description 折叠状态
   */
  collapsed: {
    type: Boolean,
    default: false
  },
  /**
   * @description 层叠顺序
   */
  zIndex: {
    type: Number,
    default: 1
  }
}

export const collapseButtonEmits = {
  'update:collapsed': (collapsed: boolean) => isBoolean(collapsed),
  change: (collapsed: boolean) => isBoolean(collapsed)
}

export type CollapseButtonProps = ExtractPropTypes<typeof collapseButtonProps>
export type CollapseButtonEmits = typeof collapseButtonEmits
  • 上面对于每个属性都明确了类型
  • 对于取值在某些值域范围内的需要进行校验
  • 有默认值的需要提供默认值
  • 如果该属性是双向绑定的,需要在事件中添加以update开头的事件
  • 每个事件都需要进行参数校验

与之对应的组件文档API部分的内容如下:

属性

参数 说明 类型 默认值 版本
direction 折叠方向,位于被折叠区域的位置 left|right|top|bottom right
collapsed(v-model) 折叠状态 boolean false
zIndex 层叠顺序 number 1

事件

事件名称 说明 回调参数 版本
change 变化时回调 collapsed

6.2 编写组件业务逻辑

在组件的组合式函数use文件中,基于定义组件属性、事件,编写组件的业务逻辑,导出相应的数据和方法,在Vue3中,我们需要谨慎分析使用ref和reactive,确保响应式符合我们的期望

  • 使用属性,直接采用props.xxx,当监控属性变化时,需采用watch(() => props.xxx, val => {})写法
  • 获取reactive定义的原生内容采用toRaw()
  • 获取全部插槽,采用useSlots()

6.3 编写组件文件

组件模板默认创建了以mapgis开头,组件名kebab-case方式的CSS类(ui组件中间多了一个-ui),新增CSS类的时候,需要符合BEM架构,以下是集中常用的方法:

// 块,以my-com的ui组件为例,形成mapgis-ui-my-com的CSS类
ns.b()
// 修饰,形成mapgis-ui-my-com--open的CSS类,修饰通过--连接
ns.m('open')
// 元素,形成mapgis-ui-my-com__item的CSS类,元素通过__连接
ns.e('item')
// 元素的修饰,形成mapgis-ui-my-com__item--actived的CSS类
ns.em('item', 'actived')

在组件脚本部分调用组合式函数后,需要解构导出的数据和方法,同时我们需要仔细分析是否符合响应式需求,原则上,我们的业务逻辑都是写在use开头的组合式函数中,组件文件中更多的是组件模板的内容,但是像ref()的使用则必须在组件文件中使用,然后再传入到业务逻辑模块中

<script setup lang="ts">
  import { ref} from 'vue'

  const formRef = ref()
  const {} = useExportFileModal(props, emit, formRef)
</script>

6.4 编写组件样式

修改style/index.less,参照BEM规范进行编写,前面的my-com组件的样式示例如下:

.mapgis-ui-my-com {
  &--open {

  }
  &__item {
    &--actived {

    }
  }
}

CSS变量的使用

整个组件库项目依赖的是Ant Design Vue 4.x的基础UI组件库,但是Ant Design Vue 4.x移除了LESS支持,采用的CSS-in-JS的写法,所以MapGIS的ui组件库将AntD的设计令牌动态转成了CSS变量,将SeedToken、MapToken、AliasToken的名称转成kebab-case形式后,增加了--mapgis前缀。比如:

borderRadius               -> var(--mapgis-border-radius)
colorBgBase                -> var(--mapgis-color-bg-base)
colorPrimary               -> var(--mapgis-color-primary)
colorTextBase              -> var(--mapgis-color-text-base)

更多Token可参考:https://antdv.com/docs/vue/customize-theme-cn#api

当我们想对项目的样式添加相关的内容时,可参考如下:

.mapgis-ui-my-com {
  background-color: var(--mapgis-color-bg-base)
  &--open {
    border: 1px solid var(--mapgis-color-border);
  }
  &__item {
    &--actived {
      color: var(--mapgis-color-primary);
    }
  }
}

在ui组件库的示例项目中提供了主题切换的功能,依靠这套CSS变量,我们可以在Ant Design设计令牌的基础上打造我们的视觉方案

6.5 增加关联组件(可选)

当该组件有强关联的组件时,可以直接在该组件目录内新增关联组件内容,可参考《4.2 组件的关联组件文件含义》进行编写。

6.6 完善组件示例

组件功能开发完毕后,需要进行测试,有条件的可以在__tests__中添加组件单元测试用例,目前我们先将重点放到由示例项目examples构建的测试框架中,不同组件库的examples项目不同,既可以设计成一个完整的系统,也可以设计成独立的示例单元,但是不管怎么样,示例用法期望能够在组件文档和组件故事中复用,避免重复开发,当前ui组件库的示例项目会自动获取组件库内的基本用法示例,并按照assets/components.json的配置进行组装。

组件库内部的examples/basic.vue是基本用法示例,我们可以为它编写更多高级的用法示例,

<template>
  <aaa></aaa>
</template>

<script setup lang="ts"></script>

尽量保持用法示例的独立性,里面依赖的自研组件和AntD组件都会在示例项目、文档项目和故事项目中进行全量注册。

6.7 完善组件文档

位于docs项目下与组件结构一致的组件文档,需要按照组件的设计进行补充,包括组件的用法部分和组件的API部分,是文档的重点内容,其中API部分要与组件的属性和事件保持一致,未来有调整的属性和事件我们还需要对版本列进行维护。组件的用法部分,默认引用了组件的基本用法,我们可以根据需要进行增加,以实际指导二次开发用户学习为目标,提高示例的可用性和覆盖度!!!

## 基本用法

<preview path="../../../../../components/my-dir/my-com/examples/basic.vue"></preview>

## 尺寸

<preview path="../../../../../components/my-dir/my-com/examples/size.vue"></preview>

## 对齐方式

<preview path="../../../../../components/my-dir/my-com/examples/align.vue"></preview>

像上述内容就表示提供了三种用法示例。

6.8 完善组件故事

组件故事是另一种展示组件文档和示例的方式,当前我们借助组件故事,更多的是展示组件的示例和用法,还没有加入更多可在线测试的交互式体验方式,在当前复用组件用法示例的基础上,需要我们给示例提供属性参数,并将参数控件化,未来有时间的话可以慢慢补充。

组件故事文件直接位于组件的结构内,在stories目录内,我们可以与组件examples下的用法示例提供一致的故事列表,如下就展示了两个组件故事:

import type { Meta, StoryObj, ArgTypes } from '@storybook/vue3'
import Basic from '../examples/basic.vue'
import Size from '../examples/size.vue'
import basicCode from '../examples/basic.vue?raw'
import sizeCode from '../examples/size.vue?raw'

const meta: Meta = {
  title: '组件/MyCom',
  tags: ['autodocs'],
  argTypes: {}
}
export default meta

type Story = StoryObj<typeof meta> & { argTypes?: ArgTypes }

export const BasicStory: Story = {
  name: '基本用法',
  args: {},
  parameters: {
    docs: {
      source: {
        code: basicCode,
        language: 'js'
      }
    }
  },
  render: args => ({
    components: { Basic },
    setup() {
      return { args }
    },
    template: `
    <Basic v-bind="args"></Basic>
    `
  })
}

export const SizeStory: Story = {
  name: '大小',
  args: {},
  parameters: {
    docs: {
      source: {
        code: sizeCode,
        language: 'js'
      }
    }
  },
  render: args => ({
    components: { Size },
    setup() {
      return { args }
    },
    template: `
    <Size v-bind="args"></Size>
    `
  })
}

参照模板很轻松就可以增加更多的故事了。

6.9 增加组件静态资源

组件内的静态资源我们直接放到components项目内,组件外的静态资源需要在示例项目、文档项目和故事项目都需要的可统一放到组件库examples/public下,项目各自的静态资源请放到各自的public内部,以下是一个组件库项目所拥有的静态资源目录,说明了哪些是公共的,哪些是私有的,以ui组件库为例:

├── components                      // 组件源码包
│   ├── aaa                         // 组件aaa
│       ├── xxx.png                 // 组件内的静态资源
│       ├── yyy.json                // 组件内的静态资源
├── docs                            // 文档项目
│   ├── public                      // 文档项目私有的静态资源
├── examples                        // 示例项目
│   ├── public                      // 公共的静态项目 + 示例项目私有的静态资源
├── storybook                       // 故事项目
│   ├── public                      // 故事项目私有的静态资源

七、组件发布和部署

7.1 组件发布

当组件开发到了一个迭代版本需要发布时,可优先发布到私有仓库进行充分测试验证后,再发布到公共仓库,各组件库内置了publish.bat发布脚本,支持传入private参数用于区分环境,并且在根package.json中提供了ui:publishui:publish:private命令,辅助我们更加方便地执行此操作。

7.2 组件部署

当组件示例、文档和故事需要部署时,需要对各个子项目进行打包构建,在组件示例中集成了文档和故事的连接,当他们部署在一起的时候,可快捷地进行跳转,各组件库内置了deploy.bat脚本,支持传入服务器的ip,辅助我们快速地将打包后的资源推送到该服务器上。

以ui组件库为例,会将静态资源全部发送到远程服务器的MapGIS-WebClient-Vue3-UI共享目录内,在该目录内会形成如下结构:

├── examples                        // 组件库示例项目静态资源
├── docs                            // 组件库文档项目静态资源
├── storybook                       // 组件库故事项目静态资源

我们在服务器上可通过Nginx对静态资源进行发布,可在Nginx的配置文件nginx.conf中增加如下内容:

	server {
        listen       8888;
        location /vue3/ui/examples {
            index  index.html;
            alias  D:/MapGIS-WebClient-Vue3-UI/examples;
            try_files $uri $uri/ /vue3/ui/examples/index.html;
        }

        location /vue3/ui/docs {
            index  index.html;
            alias  D:/MapGIS-WebClient-Vue3-UI/docs;
            try_files $uri $uri/ /vue3/ui/docs/index.html;
        }

        location /vue3/ui/storybook {
            index  index.html;
            alias  D:/MapGIS-WebClient-Vue3-UI/storybook;
            try_files $uri $uri/ /vue3/ui/storybook/index.html;
        }

        location @router {
        rewrite ^.*$ /dist/index.html last;
        }
    }

重启Nginx后,当我们访问时就可以看到全部效果了。

About

基于Vue3的MapGIS Web客户端产品

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors