个人觉得,组件库最难的不是开发,而是使用,怎么才能让组内同事都用起来,这才是关键

背景

虽然现在开源的组件库很多,但每个项目里还是或多或少都会有人封装出一些项目内通用的基础组件、业务组件

我参与过多个项目,几乎每个项目都会存在这么一种现象:重复造轮子

同一个用途的组件被不同人多次实现,导致后续维护的人可能都不知道该用哪个好,或者干脆又自己撸了一个,就又恶性循环了

至于如何解决,遇到的基本就是强制定规范,但这种靠人为主观意识的约定,很容易松动,不长久

痛点

其实可以来分析下看看,为什么就会用不起来呢?

为什么大家乐意去用一些开源组件库,就是不想用项目里别人封装的呢?

就我个人而言,可能有这么几个原因:

  • 我不知道原来项目里已经有这么个通用组件了
  • 我找到组件代码,但我不确定这个组件呈现效果是什么,是不是我想要的,对业务不熟,与其慢慢去捞页面找试用,干脆自己再撸一个
  • 我找到组件代码,也找到页面呈现效果,但我不知道该怎么使用,需要花时间去看源码

于是我反思,那我为什么会乐意去用开源组件库,比如 element-ui 组件呢:

  • 官网可以直接找到所有组件呈现效果和示例代码
  • 官网的配置项说明足够使用组件,而无需去看源码

所以对我来说,根源不是不想用同事封装的组件,而是懒得去看源码,去找示例

我更在意的是组件呈现效果和示例代码以及参数配置项说明

  • 示例代码和参数配置项说明可以通过编写 md 文档来实现
  • 组件呈现效果需要另外开发个 demo 组件来编写示例代码并运行

这意味着,封装一个组件,除了写文档,还需要再开发一个组件使用 demo,成本有些大,维护也麻烦

那么,有没有什么办法可以简化呢?

解决方案:自定义 md-loader

md-loader 是一个自定义的 webpack loader,用来解析 md 文件的,简单来说,它做了两件事:

  • 将 md 解析成 vue 组件,以便 vue 项目里可以直接将 md 当作 vue 组件使用
  • 自定义 md 语法 ::: demo,以便达到只需在 md 中编写组件示例代码,解析后的 vue 代码会自动将组件示例代码运行起来,呈现真实效果

有了 md-loader 的这两个能力,我们可以再基于 require.context 搞个自动挂载组件路由

这样一来,我们只要在每个组件目录下搞个 README.md 文档,里面贴上组件示例代码,然后运行项目,打开组件路由就可以像使用 element-ui 组件官网一样来翻看我们的组件文档了

我们还可以再集成 monaco-editor 就可以实现一个简易的在线编辑调试代码的功能

如:在线体验下

上面示例中的组件使用说明文档内容,包括呈现效果和示例代码,全程都只需要在 md 文档里编写即可,而无需额外编写其他 demo 代码,如:

# 全局弹窗 this.$rgDialog

为了避免每次使用弹窗时需要编写分散各处的片段代码(el-dialog 的模板代码,控制显隐变量,显示关闭函数等),提取封装了挂载在全局函数的弹窗 `this.$rgDialog`

直接在点击事件方法里即可完成弹窗的相关代码

## 使用示例

::: demo

```vue
<template>
<div>
<el-button type="primary" @click="showDialog">点击显示弹窗</el-button>
</div>
</template> <script>
import dialogContent from "@docs/使用说明.md";
export default {
data() {
return {};
},
mounted() {},
methods: {
showDialog() {
const rgDialog = this.$rgDialog({
props: {
title: "弹窗标题",
width: "80vw",
"close-on-click-modal": true
},
events: {},
content: dialogContent,
contentProps: {},
contentEvents: {
cancel: () => rgDialog.close()
}
}).show();
}
}
};
</script> <style lang="scss" scoped></style>
``` ::: ## options 参数说明 | 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ------------- | ----------------------------------- | ------ | ------ | ----------------------------------------------------------- |
| props | el-dialog 的 props 输入参数 | object | — | {width: '700px', top: '5vh', 'close-on-click-modal': false} |
| events | el-dialog 的输出事件,如 @opened 等 | string | — | — |
| content | 弹窗内容的 vue 组件 | object | — | — |
| contentProps | 弹窗内容 vue 组件的 props 输入参数 | object | — | — |
| contentEvents | 弹窗内容 vue 组件的输出事件 | object | — | — | ## 方法 `this.$rgDialog()` 返回的弹窗实例对象的方法: | 方法名 | 说明 | 参数 |
| ------ | -------- | ---- |
| show | 显示弹窗 | — |
| close | 关闭弹窗 | — |

md-loader 实现原理

这个 loader 是我前司一同事自己开发的,这是他的源码仓库和技术实现细节文档:

原理细节和源码可以移步到相关链接查看,这里简单概述下 md-loader 内部原理,一句话解释:

将 md 转成的 html 包裹到 vue 的 template 标签内,因此 md 可以直接被当作 vue 组件在代码里被引用,同时自定义扩展 md 的 ::: demo 语法,以便支持组件效果和示例代码可以呈现

loader 工作原理:

  1. 基于 markdown-it 系列插件将 md 转成 html
  2. 如果 md 里没有 ::: demo 场景,则直接将转成的 html 放到 vue 的 template 块里,交给 vue-loader 解析
  3. 如果有 ::: demo 场景,进入自定义解析 ::: demo 流程
    • 将 demo 里的 ```vue 代码块字符串化后放到 标签里的 highlight 插槽上。

      • 字符串化的过程做了系列代码的高亮、行号等显示处理
    • 再把 ```vue 代码块封装到单独的 vue 组件里,组件内部自动命名,然后给挂载到 标签里的 source 插槽上
    • 组件就可以用 highlight 插槽来把代码块呈现出来,同时用 source 插槽来引用 loader 生成的子组件,以达到代码块运行的效果

require.context 自动注册路由

// 递归遍历当前目录下为 .md 结尾的文件
const files = require.context(".", true, /\.md$/); files.keys().forEach((filePath) => {
// 省略根据文件路径名生成路由配置信息
// 生成路由配置相关信息,路由直接以组件目录名
const routerConfig = {
title: fileName,
path: `/${pathParts.join("/")}/${fileName}`,
component: files(filePath).default,
};
});

这样就不需要每新增一个组件, 都需要手动去注册路由信息了

注: 脚本可以借助 ChartGPT 完成, 描述好诉求就行

monaco-editor 在线代码编辑器

Vue 实现在线代码编辑和预览

小结

只需用 md 就能完成组件使用平台的搭建, 而无需再编写额外的 demo 等成本投入, 较低成本换来使用人的直观, 方便, 快捷的使用组件

自定义md-loader来简单高效的维护组件文档的更多相关文章

  1. SpringBoot整合Swagger2,再也不用维护接口文档了!

    前后端分离后,维护接口文档基本上是必不可少的工作.一个理想的状态是设计好后,接口文档发给前端和后端,大伙按照既定的规则各自开发,开发好了对接上了就可以上线了.当然这是一种非常理想的状态,实际开发中却很 ...

  2. [2013-03-14]使用wiki维护产品文档

    word文档作为产品文档的问题: word文档本身的设计是为了打印: word文档的编辑较为繁琐: 作为产品文档的word文档往往长达百页以上,难以维护,且容易分散注意力,不利于查阅: 没有一个简单易 ...

  3. python全栈开发day48-jqurey自定义动画,jQuery属性操作,jQuery的文档操作,jQuery中的ajax

    一.昨日内容回顾 1.jQuery初识 1).使用jQuery而非JS的六大理由 2).jQuery对象和js对象转换 3).jQuery的两大特点 4).jQuery的入口函数三大写法 5).jQu ...

  4. java简单实现用语音读txt文档

    最近比较无聊,随便翻着博客,无意中看到了有的人用VBS读文本内容,也就是读几句中文,emmm,挺有趣的,实现也很简单,都不需要安装什么环境,直接新建txt文件,输入一些简单的vbs读文本的代码,然后将 ...

  5. 高效查看MySQL帮助文档的方法

    在mysql的使用过程中, 可能经常会遇到以下问题: 某个操作语法忘记了, 如何快速查找? 如何快速知道当前版本上某个字段类型的取值范围? 当前版本都支持哪些函数?希望有例子说明.. 当前版本是否支持 ...

  6. 高效查看MySQL帮助文档的方法 (转)

    在mysql的使用过程中, 可能经常会遇到以下问题: 某个操作语法忘记了, 如何快速查找? 如何快速知道当前版本上某个字段类型的取值范围? 当前版本都支持哪些函数?希望有例子说明.. 当前版本是否支持 ...

  7. RAP, 高效前后端联调框架,接口文档管理工具

    RAP通过GUI工具帮助WEB工程师更高效的管理接口文档,同时通过分析接口结构自动生成Mock数据.校验真实接口的正确性,使接口文档成为开发流程中的强依赖.有了结构化的API数据,RAP可以做的更多, ...

  8. 用python批量生成简单的xml文档

    最近生成训练数据时,给一批无效的背景图片生成对应的xml文档,我用python写了一个简单的批量生成xml文档的demo,遇见了意外的小问题,记录一下. 报错问题为:ImportError: No m ...

  9. 【中文分词】简单高效的MMSeg

    最近碰到一个分词匹配需求--给定一个关键词表,作为自定义分词词典,用户query文本分词后,是否有词落入这个自定义词典中?现有的大多数Java系的分词方案基本都支持添加自定义词典,但是却不支持HDFS ...

  10. SDWebImage ReadMe.md文档简单说明

    SDWebImage ReadMe.md 文档 附:SDWebImage框架github下载地址:https://github.com/rs/SDWebImage 注1:该文章简单翻译了SDWebIm ...

随机推荐

  1. 6-MySQL查询条件

    在MySQL中,高级查询是指使用更复杂的查询语句和操作符来检索和操作数据库中的数据.高级查询可以帮助您更精确地找到所需的信息,并提高查询的效率和灵活性. 以下是高级查询的一些常见应用场景和意义: 连接 ...

  2. 主动写入流对@ResponseBody注解的影响

    问题回溯 2023年Q2某日运营反馈一个问题,商品系统商家中心某批量工具模板无法下载,导致功能无法使用(因为模板是动态变化的) 商家中心报错(JSON串): {"code":-1, ...

  3. Solution -「YunoOI 2016」镜中的昆虫

    Description Link. 区间推平: 区间数颜色. Solution 考虑无修的情况,我们是采用维护每个数的 \(pre\) 来做的.具体一点就是对于每一个 \(a_{i}\) 维护 \(p ...

  4. IP协议的发展历程

    1. IP协议 1.1为什么需要IP协议 好像ip地址就像每个人的家门号一样家喻户晓,被大家默认用来作为寻址的门牌号,起初,设计IP地址也是为了寻找某台主机,但是作为世界上家喻户晓的IPv4,大家不应 ...

  5. 解密网络通信的关键技术(下):DNS、ARP、DHCP和NAT,你了解多少?

    引言 在上一章中,我们详细介绍了域名系统(DNS)和地址解析协议(ARP)的工作原理,从而对域名解析和介质访问控制(MAC)地址寻址有了更深入的了解.在今天的章节中,我们将继续探讨动态主机配置协议(D ...

  6. snowboy 无法 install

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple snowboy Looking in indexes: https://pypi.tun ...

  7. 【PHP反序列化】速览

    PHP反序列化 一.原理 序列化就是将对象转化成字符串,反序列化相反.数据的格式转换和对象的序列化有利于对象的保存 . 反序列化漏洞:就是php对数据进行反序列化时,没有进行过滤,导致用户可以控制反序 ...

  8. [ABC205F] Grid and Tokens 题解

    Grid and Tokens 题目大意 给定 \(n\) 个点和一个 \(H\times W\) 的网格,每个点可以放置在 \((A_i,B_i)\) 到 \((C_i,D_i)\) 的矩形中或不放 ...

  9. 【虹科干货】Redis Enterprise vs ElastiCache——如何选择缓存解决方案?

    使用Redis 或 Amazon ElastiCache 来作为缓存加速已经是业界主流的解决方案,二者各有什么优势?又有哪些区别呢? 为了提高 Web 应用程序和数据驱动服务的性能与效率,使用 Red ...

  10. IOI2020 国家集训队作业 Part 1

    日期不对,但要保证顺序正确方便查找少了啥题. 计算几何和实在不会的题没写. 9.20 CF504E Misha and LCP on Tree *3000 二分,hash,树剖 CF505E Mr. ...