基于 Ant Design Pro 页面标签化展示的研究与实现 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
请不要在回答技术问题时复制粘贴 AI 生成的内容
theprimone

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

  •  
  •   theprimone
    yunsii May 15, 2021 3670 views
    This topic created in 1807 days ago, the information mentioned may be changed or developed.

    效果预览

    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 页面标签化展示这一问题重点是抛砖引玉,如果有任何意见或建议,欢迎批评指正。

    Supplement 1    May 17, 2021

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

    Supplement 2    Nov 24, 2021
    刚把基于 ant design pro V4 的标签页功能实现迁移到了 V5 欢迎有缘人试用。
    16 replies    2021-05-17 14:27:53 +08:00
    supercaizehua
        1
    supercaizehua  
       May 15, 2021
    没写参考文献,打回去重新写
    theprimone
        2
    theprimone  
    OP
       May 15, 2021
    @supercaizehua 本文不必参考任何文献 [doge]
    aaronlam
        3
    aaronlam  
       May 16, 2021
    感觉楼主这种死磕到底的精神挺值得学习的,刚开始转前端,我也是为了做需求一头扎进了 Antd Design Pro 里不能自拔,后面逐渐熟悉了前端那一套工程化的生态,才慢慢的上手。
    Kylin30
        4
    Kylin30  
       May 16, 2021
    现在第一 ui 库是哪个?
    theprimone
        5
    theprimone  
    OP
       May 16, 2021
    @aaronlam 也是后端转前端吗? Pro 的成套的技术实现认真学习一下确实能让新人快速建立起 React 开发的理论基础。不过 v2 之后开始逐渐屏蔽了越来越多的编译细节。
    theprimone
        6
    theprimone  
    OP
       May 16, 2021
    @Kylin30 应该是 Material UI,当然我是根据 star 来判断的。antd 的仓库在 3 月份被黑过一次,导致 star 全丢了,现在差不多才赶上 Material UI 的 2/3
    theprimone
        7
    theprimone  
    OP
       May 16, 2021
    啊这,这两天 antd 突然 star 起飞了,貌似重回第一了 _(:3J∠)_
    jenlors
        8
    jenlors  
       May 16, 2021
    anguiao
        9
    anguiao  
       May 16, 2021 via Android
    @long2ice 之前出问题了,这个只是恢复了以前的 star 。
    theprimone
        10
    theprimone  
    OP
       May 16, 2021
    @anguiao 我也猜测是这个原因,这两天涨得太离谱了,大佬知道哪里有恢复 star 的说明吗?
    thtznet
        11
    thtznet  
       May 17, 2021
    d2-admin 很早就写了相当成熟的标签切换逻辑,可惜基于 vue2 的 element ui,没有持续更新到 vue3
    Dragonphy
        12
    Dragonphy  
       May 17, 2021
    @thtznet d2-admin 和 d2-crud-plus 的文档写得挺靠谱,我这个 vue 都不会的撸了一套页面
    theprimone
        13
    theprimone  
    OP
       May 17, 2021
    @thtznet 看了一下效果确实挺不错的,但是个人感觉整体风格感觉怪怪的
    Incineroar
        14
    Incineroar  
       May 17, 2021
    _(:3J∠)_ 学习一下解决问题的思路,感觉比找工八股文有意思多了
    theprimone
        15
    theprimone  
    OP
       May 17, 2021
    theprimone
        16
    theprimone  
    OP
       May 17, 2021
    @Incineroar 我不是那种为了找工作专门刷题的人,都是在做自己感兴趣的项目,在过程中学习。所以我面试都是随缘的
    About     Help     Advertise     Blog     API     FAQ     Solana     5505 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 70ms UTC 09:26 PVG 17:26 LAX 02:26 JFK 05:26
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86