likes
comments
collection
share

能搞定这个antd5的css问题,你一定是css大师!

作者站长头像
站长
· 阅读数 46

咳咳,首先允许我标题党一下哈 (其实就是我调了几个小时的一个 antd-issue 中的 css 问题 我不相信有人真的能搞定它 当然也有可能是我太菜了呜呜呜

回归正题,一个小小的css至于让好吃懒做的我发一篇文章吗 其实 这个css问题可大有来头啦! 它来自于我们国内最大的React组件库 - AntDesign 且听我慢慢道来

能搞定这个antd5的css问题,你一定是css大师! 事情的起因呢 其实是某一天 AntDesign的核心贡献者 偏右大佬在某个issue下艾特了AntDesign的 Collaborators 作为AntDesign的小粉丝 我的邮箱立马收到了这个comment 能搞定这个antd5的css问题,你一定是css大师! ( Collaborators就类似于AntDesign的成员这样子

而上班正在摸鱼的我 刚好看到了这个 comment 所以立马点开这个看了一下 github.com/ant-design/…

能搞定这个antd5的css问题,你一定是css大师!

能搞定这个antd5的css问题,你一定是css大师! 好家伙 已经是三周前的issue了 而且还是AntDesign的维护者之一的大佬jianan自己提的issue 怎么没有人管呢 所以偏右大佬才艾特所有人 所以 上班摸鱼的我立马就来啦!

打开 codeSandbox 自己调试了一下发现 擦 为什么真的会闪烁一下 而且这个闪烁不是百分百复现 这用户体验直接烂掉 哒咩! 于是我就在思考 这个问题该从哪里入手

猜测一 - diff算法

什么!?diff算法是什么鬼? 咳咳 为什么会先想到这个东东呢 首先因为他是八股文(x 当然不是 首先 众所周知 像 List Tree 这种通过多种节点重复遍历得到的元素 我们需要给每个加上一个key,这样有利于 diff 算法去比较然后 update 怎么样 我八股文是不是很厉害

能搞定这个antd5的css问题,你一定是css大师! 咳咳 说歪了 这里会闪烁 说明在TreeData这个数据更新的时候 元素进行diff发现了不一样的地方所以要重新渲染 那么 我可以合理的猜想 是不是因为 这里之前的key当前更新后的key是不是不一样 导致他页面回流的成本过大 造成了这样的闪烁呢?🤔

那我们试试 前后元素的key不变会怎么样 原始数据是这样

const [treeData, setTreeData] = useState<DataNode[]>([

    {
        key: "1-1",
        title: "1-1",
        children: [
            { key: "1-1-1", title: "1-1-1" },
            { key: "1-1-2", title: "1-1-2" },
            { key: "1-1-3", title: "1-1-3" }
        ]
    
    },
    {
        key: "1-2",
        title: "1-2",
        children: [
            { key: "1-2-1", title: "1-2-1" },
            { key: "1-2-2", title: "1-2-2" },
            { key: "1-2-3", title: "1-2-3" }
        ]
    },
    {
        key: "1-3",
        title: "1-3"
    },
 ]);

出现闪烁的 Button 的删除事件是这样的

能搞定这个antd5的css问题,你一定是css大师!

现在我们把它的 key 前后保持一致

能搞定这个antd5的css问题,你一定是css大师!

这样所有元素的 key 就都没有变化啦 只有最后一个元素直接被删除了

能搞定这个antd5的css问题,你一定是css大师!

OK 本篇文章到此结束! 当然不可能啦!

能搞定这个antd5的css问题,你一定是css大师!

天真的我以为发现是事情的本质和这个 issue 的解法 这么简单!让以后的开发者保持 key 不变不就行啦! 于是就出现了这条评论 能搞定这个antd5的css问题,你一定是css大师! 当我美滋滋的准备给偏右大佬报喜的时候 突然想到 是不是该看下 antd 的底层库是不是也有这个问题 这样就能水两个pr啦! (其实为了真正确定问题的原因是处在 AntDesign 这个库还是底层的 react-component 这个库 我 clone 下来了 rc-tree 来调试 启动+本地写测试的用例 ok 看看效果

能搞定这个antd5的css问题,你一定是css大师!

太好啦!rc-tree 是没有问题的! 突然 我的邮箱收到了另一位同学的留言

能搞定这个antd5的css问题,你一定是css大师! 还在高兴的我看到这条留言愣住了 不对啊 md rc-tree 没问题说明 diff (功能) 是没问题的 说明问题根本不是上面分析的那个key啊 !!

能搞定这个antd5的css问题,你一定是css大师!

能搞定这个antd5的css问题,你一定是css大师!

那咋办呢 评论都评论了 总不能跑路吧 (也不是不行 当然不行! 那就继续找找原因

猜测二 - AntDesign层额外的类名带来的样式导致闪烁

AntDesign/tree是基于 rc-tree 开发的 rc-tree没问题说明功能是没问题的 不太可能是类似于diff啊或者中间计算啊这些原因导致的 那很可能就是由于AntDesign带来的额外样式导致的 那我们就去找找他的样式

众所周知 AntDesign5采用的是组件级别的cssinjs方案 所以想要更改组件的样式还有组件自带的样式 只需要找他组件上的 ClassNames 就可以了 于是 去源码里面找类名

找到你了 桀桀桀...(发出了反派的笑声)

能搞定这个antd5的css问题,你一定是css大师! 就这一坨 我挨个试 一个一个关掉 去看看他渲染出来的Tree在删除节点的时候会不会闪烁 终于 在我使用了对照实验法+排除法一个一个比对过去后 终于找到啦 真相只有一个!就是你 -- hashId

当去掉 hashId 之后 就不会有闪烁的情况了

能搞定这个antd5的css问题,你一定是css大师! (欣喜若狂 再看看是谁提交的 hashId

能搞定这个antd5的css问题,你一定是css大师!

糟了!是大佬 豆酱 ---g (此时的笨比小洋还不知道 hashId 是啥玩意 只知道去掉它就没有闪烁了 但是想了想 豆酱提交他肯定有他的道理 于是点开看看豆酱提交的pr

能搞定这个antd5的css问题,你一定是css大师! 晕了 这么多 这到底是个啥啊 还是直接去问豆酱算了 -- 可恶 我才不是菜鸟 (其实就是看不懂 嘿嘿

于是 笨比小洋以为他找到了答案 (推了推眼镜 真相只有一个 凶手就是你 豆酱!!!!! 能搞定这个antd5的css问题,你一定是css大师!

虽然豆酱也不知道自己做了什么 但是

能搞定这个antd5的css问题,你一定是css大师!

豆酱内心os:虽然不知道我干了啥 但是这小子气势这么强大 先鞠个躬再说

但是此时豆酱正在忙于各种issue 能搞定这个antd5的css问题,你一定是css大师! 于是我只能晚上再请教豆酱这个hashId到底是啥玩意了 能搞定这个antd5的css问题,你一定是css大师!

咳咳 言归正传!! 没有大佬 菜鸡自己琢磨 对这个hashId追根溯源 发现它来自于 @ant-design/cssinjs 这个库 这个库是 AntDesign 自己的组件级cssinjs库 这都是啥啊 组件级cssinjs库要 hashId 干啥啊 😭 于是被迫去看了AntDesign的cssinjs源码和闲夕大佬写的组件级cssinjs的文章

喵的 我理解什么是组件级cssinjs了 但是 喵的 到底啥是hashId啊!!

喵的 不管了 到点了 下班 先吃饭 等豆酱!! 终于

能搞定这个antd5的css问题,你一定是css大师!

纳尼!又没关系 为什么啊呜呜呜

能搞定这个antd5的css问题,你一定是css大师!

我已经迷了!!!都是什么跟什么啊 md

能搞定这个antd5的css问题,你一定是css大师! 等会 此时我还是有点懵的 啥?样式丢了? 对啊 md 我组件样式怎么全没了 联想到 cssinjs 和 antd 的classname 喵的 我知道了 hashid控制的是整个antd这一层ClassNames也就是说 我现在去掉 hashId 该组件的所有cssinjs的类名就就全都g了

能搞定这个antd5的css问题,你一定是css大师! 此时的我已经有点绷不住了---又错了

现在后悔还来得及吗 有这时间 我都能修几个issue了 呜呜呜呜

喵的 不能轻易言败!!继续!

猜测三 - 观察慢动作闪烁 发现 TreeNode下的后面部分整体向前漂移导致闪烁 猜测TreeNode源码机制导致

这一部分呢 就是整个TreeNode的render节点了 能搞定这个antd5的css问题,你一定是css大师! 我们可以看到 其实一个TreeNode是由这么多小节点组成的

能搞定这个antd5的css问题,你一定是css大师! 当然还有 checkbox 只是这个例子没有使用

我知道了!!一定是重新渲染的时候 前面的小节点计算过慢 导致最后一个 也就是我们最重要的文本节点 renderSelector这里函数触发之后渲染太慢了所以我只需要提前收集起来 判断前面的所有小节点是否需要渲染 如果没有任何一个小节点需要渲染 就不执行前面几个render函数 只执行最后一个renderSelector 这样不就大大节省了 前面几个render所需要的时间了吗 我真聪明 嘿嘿 说干就干

但是由于:

  1. rc-tree 是个很老的仓库了 用的是React类组件
  2. 之前是每个 render 函数里面去生成是否 render DOM 的逻辑 所以我要在 constructor 里面去重新收集一遍状态

总而言之就是 大自然的搬运工 代码过于恶心 就给大家看看一点 能搞定这个antd5的css问题,你一定是css大师! 能搞定这个antd5的css问题,你一定是css大师!

突然发现 这个没有 render 函数 我这里还不好判断他是否渲染 。。。 c

能搞定这个antd5的css问题,你一定是css大师!

算了 硬着头皮跑一下测试用例 虽然知道大概率要g

能搞定这个antd5的css问题,你一定是css大师! 这已经是测试用例挂的最少的版本了 还是挂了两个 Test Suites 寄咯!!

能搞定这个antd5的css问题,你一定是css大师! 我是谁 我在哪 😭

猜测四 - 调试一生之敌 css!!直接上手调试Style

哈哈哈哈 哈哈哈哈哈 哈哈哈哈哈哈 我没有疯!!

打开谷歌浏览器 F12 审查元素 手动编辑DOM元素 复制 删除 添加 拷贝CSS

哈哈哈哈哈 我真的没有疯 哈哈哈哈 哈哈哈哈哈 哈哈哈哈哈哈

再次打开谷歌浏览器 F12 审查元素 手动编辑DOM元素 复制 删除 添加 拷贝CSS

源码css增删改

哈哈哈哈 哈哈哈哈哈 哈哈哈哈哈哈

终于在调试很久很久之后 让我发现了关键元素<Indent> 只要删除它 就不会产生闪烁 或者在他的位置放置其他任何元素 都不会造成塌陷

能搞定这个antd5的css问题,你一定是css大师!

那就是<Indent>的原因的 塌陷的原因到底是什么呢?? 父组件的flex?子组件的宽度?属性值为0的height?? 一个一个尝试。。。。 甚至将整个rc-tree的css都搬过来也没找到答案 依旧会塌陷

终于在调试css近一个多小时后发现 只要在<Indent>加上宽度就不会塌陷了 但问题是 rc-tree的css上并没有宽度却也没有塌陷 -- 这肯定不是最终的解法 -- 最终的解法肯定是通过类似于rc-tree的css去解

但目前 通过给<Indent>加上宽度就能改变塌陷的现状

能搞定这个antd5的css问题,你一定是css大师! 于是乎 深入<Indent>源码

你能根据下图 给他加上 width 并保证通过所有测试用例吗 也就是和之前所有的case 保持一致 不会产生视图的变化 能搞定这个antd5的css问题,你一定是css大师!

5秒钟后公布本菜鸡的做法 5 4 3 2 1

能搞定这个antd5的css问题,你一定是css大师!

ok 我们看看效果:

能搞定这个antd5的css问题,你一定是css大师!

rc-tree单元测试 能搞定这个antd5的css问题,你一定是css大师! antd单元测试 能搞定这个antd5的css问题,你一定是css大师! 终于结束啦!!! 小声:虽然可能并不是最后的答案!

但是 这次bug解决之旅真的很折磨 不过解决了之后真的非常的开心!!😄

另外 附上rc-treeAntDesign/Tree **调试((的 codeSandbox 链接 codesandbox.io/s/ji-ben-an… codesandbox.io/s/kind-mata… 欢迎css大佬打开 F12 调试 Style 指出正确的css解法 我真的太想知道答案了!!

转载自:https://juejin.cn/post/7231940493256998972
评论
请登录