🌈 关于我给dumi2.0提pr的完整记录

简介: 博主最近一年时间在工作业余都在写开源组件库 concis ,其中文档站点生成框架采取了 dumi,前几天不久dumi2.0正式发布,博主也是顺势而为直接把项目升级(dumi1 -> dumi2)

您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~

前言

博主最近一年时间在工作业余都在写开源组件库 concis ,其中文档站点生成框架采取了 dumi,前几天不久dumi2.0正式发布,博主也是顺势而为直接把项目升级(dumi1 -> dumi2

由于dumi2 的站点设计比原来好看太多了,这是最吸引我的一点,附图:

image.png

不过在升级过程中还是踩了不少坑的,如果你也在使用 dumi ,具体版本迁移事项请看这里:

https://d.umijs.org/guide/upgrading

concis因为自定义了很多站点样式,因此为了不进行破坏性的升级,直接是通过链接中"拷贝源代码"的方式去迁移的,原concis的主页如图:

image.png

发现pr点

由于dumi2 最大引流点———在ant design5生产新文档中投入使用,因此在升级中也是对照了ant design的文档和源码去配置,经过一天时间,采用dumi2的文档也是勉强可以看了~

image.png

这里也是发现了几个可以改善的点:

  1. 右上角dumi2新增的RTL按钮在同时配置多语言按钮时样式显示不协调;
  2. 右侧Toc在点击时是直接通过追加哈希值采用锚点的方式定位的,而ant design在此基础加入了滚动过渡,用户体验更友好;

好!带着这两个点,说干就干!直接拉一份dumi的源码,找一下相关代码的位置。

在源码中定位

在项目目录中,很清晰可以找到前面所说的两个改善的组件位置:

image.png

解决RtlSwitch样式

先来解决第一个问题,给RtlSwitch 组件增加一些样式吧~

RtlSwitch/index.less:

@import '../LangSwitch/index.less';

html[data-direction='rtl'] {
   
   
  direction: rtl;
}

可以看到,样式中并没有增设margin相关的样式,因此这条很简单,直接给他上个样式提pr!

@import '../LangSwitch/index.less';

.@{prefix}-lang-switch {
   
   
  + & {
   
   
    margin-inline-start: 20px;
  }
}

html[data-direction='rtl'] {
   
   
  direction: rtl;
}

相关pr链接:https://github.com/umijs/dumi/pull/1305

解决Toc滚动优化

Toc/index.tsx关键代码:

return sectionRefs.length ? (
    <ScrollSpy sectionRefs={sectionRefs}>
      {({ currentElementIndexInViewport }) => {
        // for keep prev item active when no item in viewport
        if (currentElementIndexInViewport > -1)
          prevIndexRef.current = currentElementIndexInViewport;

        return (
          <ul className="dumi-default-toc">
            {toc
              .filter(({ depth }) => depth > 1 && depth < 4)
              .map((item, i) => {
                const link = `#${encodeURIComponent(item.id)}`;
                const activeIndex =
                  currentElementIndexInViewport > -1
                    ? currentElementIndexInViewport
                    : prevIndexRef.current;

                return (
                  <li key={item.id} data-depth={item.depth}>
                    <a
                      href={link}
                      title={item.title}
                      {...(activeIndex === i ? { className: 'active' } : {})}
                    >
                      {item.title}
                    </a>
                  </li>
                );
              })}
          </ul>
        );
      }}
    </ScrollSpy>
  ) : null;

可以看到,原来的方式和之前所说一样,通过a标签的href追加了url中的hash,利用html默认支持的锚点实现点击定位,而想要加入滚动,博主一开始的想法是在此基础上增设点击事件,计算页面当前高度和目标元素所在高度的高度差,做一个滚动动画的显示。

实现思路如下:

给原本a标签增加点击事件,并将所点击的h2元素id传到事件中,获取该h2元素,计算它在页面的位置,最终得出一个滚动长度,并且判定是向上还是向下滚动,通过Date差,实现一次滚动动画固定时间为35帧。

代码:

//...

const scrollTo = (newTop: number, nowTop: number, direction: 'top' | 'bottom') => {
  // 执行35次
  const duration = 450;
  const startTime = Date.now();
  const scrollDiffSize = Math.abs(newTop - nowTop);
  // 计算每帧滚动高度
  const scrollSize = direction === 'top' ? scrollDiffSize / 35 * -1 : scrollDiffSize / 35;

  const frameFunc = () => {
    const timeStamp = Date.now();
    const time = timeStamp - startTime;
    document.documentElement.scrollTop += scrollSize;

    if(time < duration) {
      raf(frameFunc)
    }
  }
  raf(frameFunc)
};

const scrollToByIndex = (h2Index: number) => {                                 
    const clickNode = sectionRefs[h2Index].current; 

    if(clickNode) {   
        // 点击目标位置                                          
        const newTop = clickNode.offsetTop                   
        const nowTop = document.documentElement.scrollTop;    
        const direction = newTop < nowTop ? 'top' : 'bottom'; 
        scrollTo(newTop, nowTop, direction);                                           
    }                                                     
};

//...

return (
  <li key={item.id} data-depth={item.depth}>
    <a
      href={link}
      onClick={() => scrollToByIndex(item.id)}
      title={item.title}
      {...(activeIndex === i ? { className: 'active' } : {})}
    >
      {item.title}
    </a>
  </li>
);

嗯.....写完以后也是觉得写的还不错,就commit上去提了pr,由于dumi维护者——peach大神的初衷是尽可能使用成熟三方库,减少维护成本,因此最后选择使用animated-scroll-to来完成动画,因此在scrollTo方法中的逻辑都可以直接使用第三方库来代替,修改后的代码如下:

//...
const scrollTo = (newTop: number) => {
  console.log(newTop)
  animateScrollTo(newTop, {
    speed: 200
  })
}

const scrollToByIndex = (h2Index: number) => {                                 
    const clickNode = sectionRefs[h2Index].current; 

    if(clickNode) {   
        // 点击目标位置                                          
        const newTop = clickNode.offsetTop;                   
        scrollTo(nowTop);                                           
    }                                                     
};

//...

return (
  <li key={item.id} data-depth={item.depth}>
    <a
      href={link}
      onClick={() => scrollToByIndex(item.id)}
      title={item.title}
      {...(activeIndex === i ? { className: 'active' } : {})}
    >
      {item.title}
    </a>
  </li>
);

嗯,此时看似需求已经完成了,可以合pr了吧?问题又出现了,由于给a标签增加了onClick事件,原本的href增设hash段实现dumi内部哈希更新失效了,最后决定下来的方案是使用dumi内置的Link组件代替a标签,实现跳转。

image.png

最终修改后的代码如下:

//...
const scrollTo = (newTop: number) => {
  console.log(newTop)
  animateScrollTo(newTop, {
    speed: 200
  })
}

const scrollToByIndex = (h2Index: number) => {                                 
    const clickNode = sectionRefs[h2Index].current; 

    if(clickNode) {   
        // 点击目标位置                                          
        const newTop = clickNode.offsetTop;                   
        scrollTo(nowTop);                                           
    }                                                     
};

//...

return (
  <li key={item.id} data-depth={item.depth}>
    <Link
      to={link}
      onClick={() => scrollToByIndex(item.id)}
      title={item.title}
      {...(activeIndex === i ? { className: 'active' } : {})}
    >
      {item.title}
    </Link>
  </li>
);

至此,实现滚动切换Toc item的优化需求就做好了~当然博主中间省略了一些代码方面的细节点,也是学习到了很多。

pr链接:https://github.com/umijs/dumi/pull/1303

效果:

rs3ii-82rfk.gif

一些心得体会

dumi2中提供了很多新特性,博主最喜欢的一个点就是通过slot自定义主题替代默认主题文件,如你不想要dumi默认的Content、Footer、Slider,你就可以像这样去自定义:

image.png

dumi dev编译过程中会判断哪些模块用默认主题,哪些去用自定义主题,这对比于dumi1来说非常大程度提高了开发成本和效率。

而像上面两个并不复杂的pr,其实完全可以通过自定义主题去fix,但换种思路想一下,作为dumi的老用户了,一起共建基层框架无非也是在提高自己的产品,并且在pr过程中也可以和维护者有近距离的交流和学习,这些都是非常有利于成长的~

具体更多的dumi2新特性可参考文章:

🎉 dumi 2,它来了它来了它来了

关于concis

最后再介绍一下博主的react组件库,从今年2月开工,目前50+组件,社区80+小伙伴一起交流讨论,如果感兴趣或喜欢或想参与共建,点个star支持一下吧~

image.png

线上文档

GitHub

如果你一起共建讨论学习,可添加博主微信:

image.png

目录
相关文章
|
9月前
|
人工智能 数据安全/隐私保护
什么样的“软技能”可以跨越周期、终身成长?
在快速变化的数字化时代,软技能成为职场人士实现终身成长的关键。本文探讨了学习能力、适应能力、沟通能力、领导力和创新思维等跨越周期的软技能,并介绍了生成式人工智能(GAI)认证作为提升软技能的新途径。GAI认证不仅涵盖技术知识,还强调软技能培养,助力职场人士增强竞争力、促进职业发展,同时强化道德与合规意识。通过系统学习与实践,个人可在未来职业生涯中脱颖而出,实现持续成长。
|
供应链 监控 搜索推荐
代购系统在面对供应链风险时,有哪些应对策略?
代购系统在面对供应链风险时,可以采取以下应对策略:建立强大的供应链网络、优化物流与配送、打造个性化服务体验、合规经营,注重风险管理、技术赋能,高效运营、深度解析风险、风险预警系统、供应链风险的分类与管理和应急预案和风险管理机制。
532 3
|
网络协议 数据库 网络架构
OSPF的LSA类型详解
OSPF的LSA类型详解
604 3
|
存储 网络协议 网络安全
开源、自建,网站与ssl证书管理
【10月更文挑战第1天】
672 3
能源转换技术
能源转换技术
345 3
|
运维 监控 物联网
物联网卡:如何选择物联网卡流量套餐
选择物联网卡(IoT SIM卡)的流量套餐时,需要根据设备的具体使用场景、数据需求量、成本预算以及长期扩展性等多方面因素进行综合考虑。以下是一些建议步骤,帮助你做出合适的选择:
|
人工智能 监控 Java
|
vr&ar Android开发 iOS开发
安卓与iOS应用开发:比较、挑战与未来趋势
本文深入探讨了安卓与iOS应用开发的各自优势、面临的挑战以及未来发展趋势。通过对开发工具、市场份额、安全性、用户体验等方面的详细比较,旨在为开发者提供全面的参考,助力其在选择开发平台时做出明智决策。同时,文章还展望了移动应用开发的前沿趋势,探讨了人工智能和物联网技术对移动应用的影响。
252 27
|
消息中间件 API 数据安全/隐私保护
就软件研发问题之RocketMQ ACL 1.0中的IP白名单存在的问题如何解决
就软件研发问题之RocketMQ ACL 1.0中的IP白名单存在的问题如何解决
229 0
|
JavaScript Java Go
【Qt】Qt编程注意事项
【Qt】Qt编程注意事项