前言
博主最近一年时间在工作业余都在写开源组件库 concis
,其中文档站点生成框架采取了 dumi
,前几天不久dumi2.0
正式发布,博主也是顺势而为直接把项目升级(dumi1
-> dumi2
)
由于dumi2
的站点设计比原来好看太多了,这是最吸引我的一点,附图:
不过在升级过程中还是踩了不少坑的,如果你也在使用 dumi
,具体版本迁移事项请看这里:
d.umijs.org/guide/upgra…
而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;
}
可以看到,样式中并没有增设margin
相关的样式,因此这条很简单,直接给他上个样式提pr!
@import '../LangSwitch/index.less';
.@{prefix}-lang-switch {+ & {margin-inline-start: 20px;}
}
html[data-direction='rtl'] {direction: rtl;
}
相关pr链接:github.com/umijs/dumi/…
解决Toc滚动优化
Toc/index.tsx关键代码:
return sectionRefs.length ? (<ScrollSpy sectionRefs={sectionRefs}>{({ currentElementIndexInViewport }) => {// for keep prev item active when no item in viewportif (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}><ahref={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}><ahref={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}><ahref={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标签,实现跳转。
最终修改后的代码如下:
//...
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}><Linkto={link}onClick={() => scrollToByIndex(item.id)}title={item.title}{...(activeIndex === i ? { className: 'active' } : {})}>{item.title}</Link></li>
);
至此,实现滚动切换Toc item
的优化需求就做好了~当然博主中间省略了一些代码方面的细节点,也是学习到了很多。
pr链接:github.com/umijs/dumi/…
效果:
最后
最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。
有需要的小伙伴,可以点击下方卡片领取,无偿分享