V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
theprimone
V2EX  ›  程序员

基于 Ant Design Pro 页面标签化展示的研究与实现

  •  
  •   theprimone ·
    yunsii · 2021-05-15 21:00:16 +08:00 · 2596 次点击
    这是一个创建于 1049 天前的主题,其中的信息可能已经有所发展或是发生改变。

    效果预览 🚀

    snapshot

    摘要

    Ant Design 作为一个昔日世界第一的 UI 库,影响力自是足够深远。而由官方推出的「开箱即用的中台前端 /设计解决方案」—— Ant Design Pro 也日趋成熟。较为遗憾的是 Ant Design Pro 官方并没有提供页面标签化展示的功能,因为当时环境的需要,我走上了这条页面标签化的不归路……

    关键词:Ant Design ProUmi标签页页面标签化

    绪论

    从 19 年偶然发现了 Ant Design Pro (以下简称 Pro )以来,对我的技术发展有着不容忽视的影响,当然本文着重讨论我在页面标签化展示的研究与实现。刚接触 Pro 的时候自己还是一个工作中用 Java,业余学习 React 而转型前端的毕业一年的菜鸟。突然面对 Pro 这样一个庞杂的脚手架(当时的版本 Pro v2 ),而且还要做一个自己本来毫无头绪的功能时,我是拒绝的,奈何没人顶上只能自己硬着头皮搞了。

    道路是崎岖的

    一切的起点都要从一个不得不提的官方仓库关于此讨论甚多的 issue ——能否提供 tab 切换模式说起。感谢其中相关的仓库提供的思路。当时研究了好几个仓库的源码,主要有两个思路:

    • 读取路由配置生成一个扁平的路由映射,再为其他激活页面的组件注入点击事件回调;
    • 拦截 children,子组件缓存不同路由下的 children,再根据当前的 location 渲染对应的组件。

    第一个思路是通过点击事件来更新标签页的渲染,对其他组件还存在一定的侵入性,实现不够优雅,更为尴尬的是不支持页面的嵌套路由渲染(后来知道了路由配置中的组件其实是 Switch 组件时,应该也能实现嵌套路由渲染)。

    第二个思路就没有了对于其他组件的侵入性,只需要监听 childrenlocation 的变化即可。印象中由于彼时 hooks 还未发布,通过类组件实现颇为繁琐。hooks 正式发布后又重构成了函数式组件实现。

    前途是光明的

    snapshot

    近两年的时间里随着各方面的不断成熟,当前实现 Ant Design Pro Plus 已经支持了足够丰富的功能:

    • 支持页面的嵌套路由渲染
    • 两种标签页模式可选
      • 基于路由,每个路由只渲染一个标签页
      • 基于路由参数,计算出每个路由的所有参数的哈希值,不同的哈希值渲染不同的标签页
    • 可固定标签栏
    • 快捷操作
      • 刷新标签页 - window.reloadTab()
      • 关闭标签页 - window.closeTab()
      • 返回之前标签页 - window.goBackTab()
      • 关闭并返回之前标签页 - window.closeAndGoBackTab()
    • reloadable,支持在头部操作栏刷新当前标签页
    • follow,路由定义中新增配置,默认打开方式是添加到所有标签页最后面,可通过配置该属性,使得一个标签页在 follow 指定的标签页后面打开(可参考查询页 Demo )
    • persistent,支持页面刷新之后恢复上次的标签页状态

    得益于 hooks 功能的加持,封装了 useTabs 的 hook,核心功能一目了然。如此,只需要根据状态渲染标签页即可。

    核心逻辑

    作为一个不那么简单的功能,需要注意的细节自然不少,这里重点介绍两个核心函数。

    getOriginalRenderRoute

    根据 location 和原始的路由定义解析出待渲染的路由定义对象 RenderRoute,**核心是算出正确的 renderKey**,标签页的唯一性主要由其决定(基于路由参数的标签页还需要结合哈希值)。

    getOriginalRenderRoute

    注释应该还算清晰,尽力覆盖了一些我所能考虑到的各种情况。特别的是做了一个缓存,避免反复计算 renderKey

    withRouteTab

    页面性能优化高阶函数。默认情况下,每次切换都会触发所有标签页的渲染,当打开标签页太多且页面较为复杂时,由于没有必要的渲染可能会造成操作标签页时有明显的反馈延迟,可通过此高阶函数包裹页面组件以优化渲染性能。

    一个难题

    近两年的发展并不是一帆风顺,很多问题都算是不痛不痒,一个萝卜一个坑都能解决,但是一个关于 Umi 的难题折磨了我很长的时间。

    Umi 升级到 3.0 的时候也尝试升级项目的 Umi 版本,不升不知道,一升吓一跳,切换时所有标签页都会渲染成当前 location 对应的页面内容,当时我就震惊了,不禁陷入了哲学三问:我是谁?我在哪儿?我要干嘛?

    相当长的一段时间都毫无头绪,也提了 issue —— 「想了解一下 umi 2 与 3 对路由组件处理的异同」,没有得到反馈 _(:3J∠)_ 直到感觉被 Umi 抛下了好远好远,无奈再次硬着头皮研究了 Umi 两个版本之间关于路由渲染的源码,功夫不负有心人,最后终于找到了病根,成功升级 Umi 的版本,这也是该功能仅支持 ^[email protected] | ^[email protected] 的原因。

    总结

    对比已知的其他实现要么断更,要么功能不够完善,要么二者兼备。一个功能维护了近两年,之所以开篇提到「我走上了这条页面标签化的不归路」也正是这个原因,好在现在思路越来越清晰了。

    正是在输出这篇文章的时候,突然想到可以将前文提到的两种思路整合,貌似也是个不错的方案,即只监听 location 并移除 children 的依赖。不过后续的重点可能还是侧重于将此功能插件化集成到 Umi 中。

    前端一出道就碰到了 Pro,应该算是一大幸事了。以此为基础,对于前端开发的技术栈有了一系列较为成熟的认识,同时培养了较好的开发习惯,也为后续的自身技术上的可持续发展提供了源源不断的动力。当然,由于自身能力所限,过程中可能会有不足之处,对于 Pro 页面标签化展示这一问题重点是抛砖引玉,如果有任何意见或建议,欢迎批评指正。

    第 1 条附言  ·  2021-05-17 20:33:42 +08:00

    [勘误] 实现思路中的第一个有误。应该移除“(后来知道了路由配置中的组件其实是 Switch 组件时,应该也能实现嵌套路由渲染)”。路由配置中为单纯的页面组件或者 LoadableComponent。

    第 2 条附言  ·  2021-11-24 00:00:33 +08:00
    刚把基于 ant design pro V4 的标签页功能实现迁移到了 V5 欢迎有缘人试用。
    16 条回复    2021-05-17 14:27:53 +08:00
    supercaizehua
        1
    supercaizehua  
       2021-05-15 21:04:55 +08:00
    没写参考文献,打回去重新写
    theprimone
        2
    theprimone  
    OP
       2021-05-15 21:25:58 +08:00
    @supercaizehua 本文不必参考任何文献 [doge]
    aaronlam
        3
    aaronlam  
       2021-05-16 00:31:56 +08:00
    感觉楼主这种死磕到底的精神挺值得学习的,刚开始转前端,我也是为了做需求一头扎进了 Antd Design Pro 里不能自拔,后面逐渐熟悉了前端那一套工程化的生态,才慢慢的上手。
    Kylin30
        4
    Kylin30  
       2021-05-16 05:16:22 +08:00
    现在第一 ui 库是哪个?
    theprimone
        5
    theprimone  
    OP
       2021-05-16 08:55:35 +08:00
    @aaronlam 也是后端转前端吗? Pro 的成套的技术实现认真学习一下确实能让新人快速建立起 React 开发的理论基础。不过 v2 之后开始逐渐屏蔽了越来越多的编译细节。
    theprimone
        6
    theprimone  
    OP
       2021-05-16 09:00:32 +08:00
    @Kylin30 应该是 Material UI,当然我是根据 star 来判断的。antd 的仓库在 3 月份被黑过一次,导致 star 全丢了,现在差不多才赶上 Material UI 的 2/3 😂
    theprimone
        7
    theprimone  
    OP
       2021-05-16 11:08:31 +08:00
    啊这,这两天 antd 突然 star 起飞了,貌似重回第一了 _(:3J∠)_
    jenlors
        8
    jenlors  
       2021-05-16 14:05:01 +08:00
    anguiao
        9
    anguiao  
       2021-05-16 18:54:09 +08:00 via Android
    @long2ice 之前出问题了,这个只是恢复了以前的 star 。
    theprimone
        10
    theprimone  
    OP
       2021-05-16 19:01:02 +08:00
    @anguiao 我也猜测是这个原因,这两天涨得太离谱了,大佬知道哪里有恢复 star 的说明吗?
    thtznet
        11
    thtznet  
       2021-05-17 08:57:33 +08:00
    d2-admin 很早就写了相当成熟的标签切换逻辑,可惜基于 vue2 的 element ui,没有持续更新到 vue3
    Dragonphy
        12
    Dragonphy  
       2021-05-17 09:05:38 +08:00
    @thtznet d2-admin 和 d2-crud-plus 的文档写得挺靠谱,我这个 vue 都不会的撸了一套页面
    theprimone
        13
    theprimone  
    OP
       2021-05-17 09:33:26 +08:00
    @thtznet 看了一下效果确实挺不错的,但是个人感觉整体风格感觉怪怪的 😂
    Incineroar
        14
    Incineroar  
       2021-05-17 14:20:09 +08:00
    _(:3J∠)_ 学习一下解决问题的思路,感觉比找工八股文有意思多了
    theprimone
        15
    theprimone  
    OP
       2021-05-17 14:25:58 +08:00
    theprimone
        16
    theprimone  
    OP
       2021-05-17 14:27:53 +08:00
    @Incineroar 我不是那种为了找工作专门刷题的人,都是在做自己感兴趣的项目,在过程中学习。所以我面试都是随缘的 😂
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2836 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 14:35 · PVG 22:35 · LAX 07:35 · JFK 10:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.