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


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

    前言

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

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

    在这里插入图片描述

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

    dumi1 -> dumi2迁移指南

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

    在这里插入图片描述

    发现pr点

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

    在这里插入图片描述

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

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

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

    在源码中定位

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

    在这里插入图片描述

    解决RtlSwitch样式

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

    RtlSwitch/index.less:

    @import '../LangSwitch/index.less';
    
    html[data-direction='rtl'] {
      direction: rtl;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    @import '../LangSwitch/index.less';
    
    .@{prefix}-lang-switch {
      + & {
        margin-inline-start: 20px;
      }
    }
    
    html[data-direction='rtl'] {
      direction: rtl;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    解决Toc滚动优化

    Toc/index.tsx关键代码:

    return sectionRefs.length ? (
        
          {({ currentElementIndexInViewport }) => {
            // for keep prev item active when no item in viewport
            if (currentElementIndexInViewport > -1)
              prevIndexRef.current = currentElementIndexInViewport;
    
            return (
              
      {toc .filter(({ depth }) => depth > 1 && depth < 4) .map((item, i) => { const link = `#${encodeURIComponent(item.id)}`; const activeIndex = currentElementIndexInViewport > -1 ? currentElementIndexInViewport : prevIndexRef.current; return (
    • {item.title}
    • ); })}
    ); }}
    ) : null;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    可以看到,原来的方式和之前所说一样,通过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 (
      
  • scrollToByIndex(item.id)} title={item.title} {...(activeIndex === i ? { className: 'active' } : {})} > {item.title}
  • );
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    嗯…写完以后也是觉得写的还不错,就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 (
      
  • scrollToByIndex(item.id)} title={item.title} {...(activeIndex === i ? { className: 'active' } : {})} > {item.title}
  • );
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

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

    在这里插入图片描述

    最终修改后的代码如下:

    //...
    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 (
      
  • scrollToByIndex(item.id)} title={item.title} {...(activeIndex === i ? { className: 'active' } : {})} > {item.title}
  • );
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

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

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

    效果:

    在这里插入图片描述

    一些心得体会

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

    在这里插入图片描述

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

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

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

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

    关于concis

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

    在这里插入图片描述

    线上文档

    GitHub

  • 相关阅读:
    源码级别的广播与监听实现
    独立开发者知识贴
    modinfo对比内核版本号
    题解 [LuoguP3426][POI2005]SZA-Template
    (笔记整理未完成)【图论】无向图求割点、割边
    Spring MVC中如何获取Request,Response对象方法呢?
    [NOIP2000 提高组]-乘积最大:隔板法-DFS搜索-Go语言
    webrtc H265 网页播放器迈向实用第一步
    【解刊】Elsevier旗下CCF-B类,3区SCI,见刊快,值得投吗?
    c# 定时器
  • 原文地址:https://blog.csdn.net/m0_46995864/article/details/128029589