记一次给ant-design-vue组件库提pr的经历

在这里插入图片描述

前排围观指路:https://github.com/vueComponent/ant-design-vue/pull/6173
参照5W1H分析法解释下为什么要提这个pr?

  • what?何事?ant-design-vue(下文以antv简称)是ant-design(下文以antd简称)的vue实现,组件的风格和antd保持同步。
  • why?何因?因为,antd自@4.2.0版本提供了分段控制器(segmented)组件,而antv还没有更新该组件。分段控制器(Segmented/Segmented Control)用于展示多个选项及其相关的信息,并允许用户选择其中单个选项,查看信息。
  • when?何时?想法产生大概是十一月下旬,中间偷懒+感染生病耽搁一段时间,大致时间就是十一月底到十二月底,是真能拖沓。
  • where?何地?“今大道既隐,天下为家”-《礼记·礼运》,当然是哪里都可以。
  • who?何人?嘿嘿!重铸xx荣光,吾辈义不容辞。
  • how?怎样做?因为两个组件库都有在使用,当时发现antv没有segmented这个组件(现在更多了,antd更新了5.x版本,新增了一些组件),好奇翻了下github的Issue和Pullrequest,确认了确实没有这个组件,但当时没有任何想法,十一月下旬一次吃饭的路上突然有了尝试给组件库提pr这个想法,和朋友聊了下觉得切实可行,后来想想之所以会产生这个样的想法,是因为加了闲D阿强大佬的QQ群,群里的人间和深红大佬堪称开源积极份子,经常在群里分享给组件库提pr和造轮子的事宜,人间大佬还是antd的开发团队成员,应该是他们的行为触动到我了吧,扯远了…,关于怎样做,最初的想法就是1.antd已经有完整实现了;2.segmented其实与tabs相差不大;有antd珠玉在前,也可以参考antv的tabs是如何实现的,迁移这个组件应该不难,但是现实是图样图森破,人还是太年轻,不能太盲目自信。

遇到的问题一:

antd看起来是一个组件库,但实际上他的部分组件是在react-component这个仓库中,如下图的antd的package.json,以rc-segmented为例,他还同时引用了rc-motion与rc-util,也就是说看起来是一个组件库,实际上是四个组件库,层层套娃,不过这也不算太大的问题,挨个挨个找,也能达到目的
在这里插入图片描述

遇到的问题二:

通过浏览的控制台我们可以很方便的拿到组件的样式,可以省去很大的功夫,毕竟从零实现一个组件想想都很头大,但是有一点我很困惑,就是:where(.css-xxxx),这个.css-xx是什么东东,where语法我知道,里面是他的条件,但这个条件究竟是什么呢,求助了下人间大佬,原来这个值是hashid,为了不和v4冲突所以加的哈希值,不过这边貌似用不到,所以这个就可以直接pass了,哇真的有人可以问真的太爽了,不然光靠自己想怎么也想不到,因为不会考虑到版本冲突,有了样式我们就可以直接实现一个简单的demo了,嘿嘿,有几分相似了
在这里插入图片描述

<div class="ant-segmented">
  <div class="ant-segmented-group">
    <div id="test"></div>
    <label class="ant-segmented-item ant-segmented-item-selected">
      <div class="ant-segmented-item-label">
        <div>vue</div>
      </div>
    </label>
    <label class="ant-segmented-item">
      <div class="ant-segmented-item-label">
        <div>react</div>
      </div>
    </label>
    <label class="ant-segmented-item">
      <div class="ant-segmented-item-label">
        <div>angular</div>
      </div>
    </label>
  </div>
</div>

<script>
function segmentedSwitch() {
    let segmented = document.querySelectorAll(".ant-segmented-group > label");
    let test = document.querySelector('#test')
    for (let i = 0; i < segmented.length; i++) {
        segmented[i].index = i;  
        const calcThumbStyle = {
          left: segmented[i].offsetLeft,
          width: segmented[i].clientWidth
        }
        segmented[i].onclick = function () {
            for (let j = 0; j < segmented.length; j++) {
                segmented[j].classList.remove('ant-segmented-item-selected')
                //test.classList.remove('ant-segmented-thumb',  'ant-segmented-thumb-motion-appear-active')
                //test.removeAttribute("style")
            }
            this.classList.add('ant-segmented-item-selected')
            //test.classList.add('ant-segmented-thumb',  'ant-segmented-thumb-motion-appear-active')
            //test.style.cssText = `transform: translateX(${calcThumbStyle.left}); width: ${calcThumbStyle.width}`
        }
        console.log(calcThumbStyle)
    }
}
segmentedSwitch()
</script>

<style>
.ant-segmented{
    box-sizing:border-box;
    margin:0;
    padding:2px;
    color:rgba(0, 0, 0, 0.65);
    font-size:14px;
    line-height:1.5714285714285714;
    list-style:none;
    font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';
    display:inline-block;
    background-color:#f5f5f5;
    border-radius:6px;
    transition:all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.ant-segmented .ant-segmented-group{
    position:relative;
    display:flex;
    align-items:stretch;
    justify-items:flex-start;
    width:100%;
}
.ant-segmented .ant-segmented-item-selected{
    background-color:#ffffff;
    box-shadow:0 1px 2px 0 rgba(0, 0, 0, 0.03),0 1px 6px -1px rgba(0, 0, 0, 0.02),0 2px 4px 0 rgba(0, 0, 0, 0.02);
    color:rgba(0, 0, 0, 0.88);
}
.ant-segmented .ant-segmented-item{
    position:relative;
    text-align:center;
    cursor:pointer;
    transition:color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
    border-radius:4px;
    user-select: none;
}
.ant-segmented .ant-segmented-item::after{
  content:"";
  position:absolute;
  width:100%;
  height:100%;
  top:0;
  inset-inline-start:0;
  border-radius:4px;
  transition:background-color 0.2s;
}
.ant-segmented-item:hover:not(.ant-segmented-item-selected):not(.ant-segmented-item-disabled) {
  color:rgba(0, 0, 0, 0.88);
}
.ant-segmented-item:hover:not(.ant-segmented-item-selected):not(.ant-segmented-item-disabled)::after{
    background-color:rgba(0, 0, 0, 0.06);
}
.ant-segmented .ant-segmented-item-label{
    min-height:28px;
    line-height:28px;
    padding:0 11px;
    overflow:hidden;
    white-space:nowrap;
    text-overflow:ellipsis;
}
.ant-segmented-disabled .ant-segmented-item,.ant-segmented-disabled .ant-segmented-item:hover,.ant-segmented-disabled .ant-segmented-item:focus{
    color:rgba(0, 0, 0, 0.25);
    cursor:not-allowed;
}
.ant-segmented .ant-segmented-item-disabled,.ant-segmented .ant-segmented-item-disabled:hover,.ant-segmented .ant-segmented-item-disabled:focus{
    color:rgba(0, 0, 0, 0.25);
    cursor:not-allowed;
}
.ant-segmented .ant-segmented-thumb{
    background-color:#ffffff;
    box-shadow:0 1px 2px 0 rgba(0, 0, 0, 0.03),0 1px 6px -1px rgba(0, 0, 0, 0.02),0 2px 4px 0 rgba(0, 0, 0, 0.02);
    position:absolute;
    inset-block-start:0;
    inset-inline-start:0;
    width:0;
    height:100%;
    padding:4px 0;
    border-radius:4px;
}
.ant-segmented .ant-segmented-thumb~.ant-segmented-item:not(.ant-segmented-item-selected):not(.ant-segmented-item-disabled)::after{
    background-color:#ffffff;
}
.ant-segmented .ant-segmented-thumb-motion-appear-active{
    transition:transform 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
    will-change:transform,width;
}

</style>

遇到的问题三:

antv是使用的jsx构建组件,在vue中写jsx和在react中写jsx还是有些不一样的,这里可以直接看官方的vuejs/babel-plugin-jsx: JSX for Vue 3 (github.com)就好,如何在jsx中使用v-show、v-model、slot这些眼熟的小伙伴们,网络不好可以看cnpmPackage - @vue/babel-plugin-jsx (npmmirror.com)

遇到的问题四:

我没有提过pr的经历(┬┬﹏┬┬),做过与开源最相关的事大概就是使用组件库吧,哈哈,百度了一番,我觉得这篇文章蛮好的如何参与开源项目 - 细说 GitHub 上的 PR 全过程 (qq.com),相关的可以从5.1看起走,过程大致如下:

  1. Fork项目仓库到自己的账号下
  2. 克隆自己账号下的项目到本地
  3. 下载依赖后开始魔改,但是建议新建一个分支,直接改main分支不太好
  4. 按照commit规范提交代码,然后push到仓库,推之前先拉取下最新代码
  5. GitHub会提示可以开一个Pullrequest,点击之后会跳转到Fork的仓库本体的Pullrequest区,按照pr模板填写描述,然后点击创建pr即可
  6. 最后就是等待了,通过被合入不通过被拒绝

总体来看流程还是蛮简单的,只要代码合规即可

遇到的问题五:

光通过jsx实现组件还不够,需要通过demo展示出来,通过摸索其他组件的demo,需要做如下的事情:

  1. 组件文件夹(如segmented)下新建demo文件夹,在其中新建demo案例,通过index.vue引入和暴露出去,官方已经做好了demo的展示样式,通过demo-sort包裹即可,category应该是字面意思,type就是放在左侧导航栏哪一块里面,titlesubTitle就是左侧导航栏的正副标题,还需要把中、英文档引入,
-- components
    |-- segmented
        |-- demo
            |-- basic.vue
            |-- index.vue
        |-- index.ts
        |-- index.en-US.md
        |-- index.zh-CN.md
 // index.vue
<template>
  <demo-sort>
    <basic />
  </demo-sort>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import CN from '../index.zh-CN.md';
import US from '../index.en-US.md';
import Basic from './basic.vue';

export default defineComponent({
  components: { Basic },
  category: 'Components',
  subtitle: '分段控制器',
  type: 'Data Display',
  title: 'Segmented',
  CN,
  US,
});
</script>

demo案例中的doc标签就是文档,order是demo-sort用来排序的,title是demo与描述之间分割线中的内容,zh-CN、en-US是demo下方的描述,不是index.vue中引入的CN、US文件,CN、US中是组件的描述、分类和API这些

<docs>
---
order: 0
title:
  zh-CN: 基本用法
  en-US: Basic Usage
---

## zh-CN
最简单的用法。

## en-US
The most basic usage.
</docs>

<template>
  <a-segmented options="['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly']" />
</template>
  1. components文件夹下有components.ts、style.ts两个文件,分别将组件、组件props和组件样式暴露和导入即可
-- components
    |-- components.ts
    |-- style.ts
// components.ts
export type { SegmentedProps } from './segmented';
export { default as Segmented } from './segmented';
// style.ts
import './segmented/style';
  1. antv的前端页面是放在site文件下,我们需要修改的地方有两处site/src/router/demoRouters.js(添加demo路由)、site/src/demo.js(添加demo描述)
-- site
    |-- src
        |-- router
            |-- demoRoutes.js
        |-- demo.js
// demoRoutes.js
export default [
    {
      path: 'segmented:lang(-cn)?',
      meta: {"category":"Components","type":"数据展示","title":"Segmented","subtitle":"分段控制器"},
      component: () => import('../../../components/segmented/demo/index.vue'),
    },
]
// demo.js
export default {
    segmented: {
      category: 'Components',
      subtitle: '分段控制器',
      type: 'Data Display',
      title: 'Segmented',
    },
}
  1. 修改了这些就可以看到demo效果啦
    在这里插入图片描述

遇到的问题六:

单元测试,这个是组件库必备的,antv采用了@vue/test-utils、@vue/vue3-jest配合jest来做,这块确实是我比较薄弱的,没有写过单元测试说老实话,后续会针对这块好好学习下

最后

这将近一个月下来,因为懒惰拖了很久,然后感染生病确实不在状态鸽了一周,好在还是跌跌撞撞把这个写完,当pr提交的那一刻,有些激动、有些释然,pr能不能被通过已经不重要了(大概率要pass,写文的时候发现错漏了一些(┬┬﹏┬┬),当时检查没太仔细),不过这次经历还是让我学到了很多,第一次提交pr、vue中jsx的运用、组件的封装、API的考虑等等,感谢编程路上为我提供过帮助的大佬们

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值