能搞定这个antd5的css问题,你一定是css大师!
咳咳,首先允许我标题党一下哈 (其实就是我调了几个小时
的一个 antd-issue 中的 css 问题
我不相信有人真的能搞定它 当然也有可能是我太菜了呜呜呜
回归正题,一个小小的css至于让好吃懒做的我发一篇文章吗 其实 这个css问题可大有来头
啦!
它来自于我们国内最大的React组件库 - AntDesign
且听我慢慢道来
事情的起因呢 其实是某一天
AntDesign的核心贡献者
偏右
大佬在某个issue下艾特了AntDesign的 Collaborators
作为AntDesign的小粉丝 我的邮箱立马收到了这个comment
( Collaborators就类似于AntDesign的成员这样子
而上班正在摸鱼的我 刚好看到了这个 comment 所以立马点开这个看了一下 github.com/ant-design/…
好家伙 已经是
三周前
的issue了 而且还是AntDesign的维护者之一的大佬jianan
自己提的issue
怎么没有人管
呢 所以偏右大佬才艾特所有人
所以 上班摸鱼的我立马就来啦!
打开 codeSandbox 自己调试了一下发现 擦 为什么真的会闪烁一下 而且这个闪烁不是百分百复现 这用户体验直接烂掉 哒咩! 于是我就在思考 这个问题该从哪里入手
猜测一 - diff算法
什么!?diff算法是什么鬼?
咳咳 为什么会先想到这个东东呢 首先因为他是八股文(x
当然不是 首先 众所周知 像 List
Tree
这种通过多种节点重复遍历得到的元素 我们需要给每个加上一个key
,这样有利于 diff 算法去比较然后 update
怎么样 我八股文是不是很厉害
咳咳 说歪了 这里会闪烁 说明在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 的删除事件
是这样的
现在我们把它的 key 前后保持一致
这样所有元素的 key 就都没有变化啦 只有最后一个元素直接被删除了
OK 本篇文章到此结束! 当然不可能啦!
天真的我以为发现是事情的本质和这个 issue 的解法
这么简单!让以后的开发者保持 key 不变
不就行啦!
于是就出现了这条评论
当我美滋滋的准备给偏右大佬报喜的时候 突然想到 是不是该看下 antd 的底层库是不是也有这个问题 这样就能水两个pr啦!
(其实为了真正确定问题的原因是处在
AntDesign
这个库还是底层的 react-component
这个库
我 clone 下来了 rc-tree
来调试 启动+本地写测试的用例
ok 看看效果
太好啦!rc-tree
是没有问题的!
突然 我的邮箱收到了另一位同学的留言
还在高兴的我看到这条留言愣住了 不对啊 md
rc-tree 没问题说明 diff (功能) 是没问题的 说明问题
根本不是
上面分析的那个key啊 !!
那咋办呢 评论都评论了 总不能跑路吧 (也不是不行 当然不行! 那就继续找找原因
猜测二 - AntDesign层额外的类名带来的样式导致闪烁
AntDesign/tree
是基于 rc-tree
开发的 rc-tree没问题说明功能是没问题的 不太可能是类似于diff啊或者中间计算啊这些原因导致的 那很可能就是由于AntDesign带来的额外样式导致的
那我们就去找找他的样式
众所周知 AntDesign5
采用的是组件级别的cssinjs方案
所以想要更改组件的样式还有组件自带的样式 只需要找他组件上的 ClassNames
就可以了
于是 去源码里面找类名
找到你了 桀桀桀...(发出了反派的笑声)
就这一坨 我挨个试
一个一个关掉 去看看他渲染出来的Tree在删除节点的时候会不会闪烁
终于 在我使用了
对照实验法
+排除法
一个一个比对过去后 终于找到啦
真相只有一个!就是你 -- hashId
当去掉 hashId
之后 就不会有闪烁的情况了
(欣喜若狂 再看看是谁提交的
hashId
糟了!是大佬 豆酱
---g
(此时的笨比小洋还不知道 hashId
是啥玩意 只知道去掉它就没有闪烁了
但是想了想 豆酱提交他肯定有他的道理
于是点开看看豆酱提交的pr
晕了 这么多 这到底是个啥啊 还是直接去问豆酱算了 -- 可恶 我才不是菜鸟 (其实就是看不懂 嘿嘿
于是 笨比小洋以为他找到了答案
(推了推眼镜 真相只有一个 凶手就是你 豆酱!!!!!
虽然豆酱也不知道自己做了什么 但是
豆酱内心os:虽然不知道我干了啥 但是这小子气势这么强大 先鞠个躬再说
但是此时豆酱正在忙于各种issue
于是我只能晚上再请教豆酱这个hashId到底是啥玩意了
咳咳 言归正传!!
没有大佬 菜鸡自己琢磨 对这个hashId追根溯源 发现它来自于 @ant-design/cssinjs 这个库
这个库是 AntDesign 自己的组件级cssinjs库
这都是啥啊 组件级cssinjs库要 hashId
干啥啊 😭
于是被迫去看了AntDesign的cssinjs源码和闲夕大佬写的组件级cssinjs的文章
喵的 我理解什么是组件级cssinjs了 但是 喵的 到底啥是hashId啊!!
喵的 不管了 到点了 下班 先吃饭 等豆酱!! 终于
纳尼!又没关系 为什么啊呜呜呜
我已经迷了!!!都是什么跟什么啊 md
等会 此时我还是有点懵的 啥?
样式丢了
?
对啊 md 我组件样式怎么全没了
联想到 cssinjs 和 antd 的classname
喵的 我知道了 hashid控制的是整个antd这一层
的ClassNames
也就是说 我现在去掉 hashId
该组件的所有cssinjs的类名就就全都g了
此时的我已经有点绷不住了---又错了
现在后悔还来得及吗 有这时间 我都能修几个issue了 呜呜呜呜
喵的 不能轻易言败!!继续!
猜测三 - 观察慢动作闪烁 发现 TreeNode下的后面部分整体向前漂移导致闪烁 猜测TreeNode源码机制导致
这一部分呢 就是整个TreeNode的render节点了
我们可以看到 其实一个TreeNode是由这么多小节点组成的
当然还有
checkbox
只是这个例子没有使用
我知道了!!一定是重新渲染的时候 前面的小节点计算过慢
导致最后一个 也就是我们最重要的文本节点 renderSelector
这里函数触发之后渲染太慢了所以我只需要提前收集起来 判断前面的所有小节点是否需要渲染
如果没有任何一个小节点需要渲染 就不执行前面几个render函数 只执行最后一个renderSelector
这样不就大大节省了 前面几个render所需要的时间了吗 我真聪明 嘿嘿
说干就干
但是由于:
rc-tree
是个很老的仓库了 用的是React类组件
- 之前是每个 render 函数里面去生成是否 render DOM 的逻辑 所以我要在
constructor
里面去重新收集一遍状态
总而言之就是 大自然的搬运工 代码过于恶心 就给大家看看一点
突然发现 这个没有 render
函数 我这里还不好判断他是否渲染 。。。 c
算了 硬着头皮跑一下测试用例 虽然知道大概率要g
这已经是测试用例挂的最少的版本了 还是挂了两个
Test Suites
寄咯!!
我是谁 我在哪 😭
猜测四 - 调试一生之敌 css!!直接上手调试Style
哈哈哈哈 哈哈哈哈哈 哈哈哈哈哈哈 我没有疯!!
打开谷歌浏览器 F12 审查元素 手动编辑DOM元素 复制 删除 添加 拷贝CSS
哈哈哈哈哈 我真的没有疯 哈哈哈哈 哈哈哈哈哈 哈哈哈哈哈哈
再次打开谷歌浏览器 F12 审查元素 手动编辑DOM元素 复制 删除 添加 拷贝CSS
源码css增删改
哈哈哈哈 哈哈哈哈哈 哈哈哈哈哈哈
终于在调试很久很久之后 让我发现了关键元素<Indent>
只要删除它 就不会产生闪烁
或者在他的位置放置其他任何元素 都不会造成塌陷
那就是<Indent>
的原因的 塌陷的原因到底是什么呢??
父组件的flex?子组件的宽度?属性值为0的height??
一个一个尝试。。。。
甚至将整个rc-tree的css都搬过来也没找到答案 依旧会塌陷
终于在调试css近一个多小时后发现 只要在<Indent>
加上宽度
就不会塌陷了 但问题是 rc-tree的css上并没有宽度却也没有塌陷 -- 这肯定不是最终的解法
-- 最终的解法肯定是通过类似于rc-tree的css
去解
但目前 通过给<Indent>
加上宽度
就能改变塌陷的现状
于是乎 深入
<Indent>
源码
你能根据下图 给他加上 width 并保证通过所有测试用例吗
也就是和之前所有的case 保持一致 不会产生视图的变化
5秒钟后公布本菜鸡的做法 5 4 3 2 1
ok 我们看看效果:
rc-tree
单元测试
antd
单元测试
终于结束啦!!! 小声:虽然可能并不是最后的答案!
但是 这次bug解决之旅真的很折磨
不过解决了之后真的非常的开心
!!😄
另外 附上rc-tree
与AntDesign/Tree
**调试((的 codeSandbox 链接
codesandbox.io/s/ji-ben-an…
codesandbox.io/s/kind-mata…
欢迎css大佬打开 F12 调试 Style 指出正确的css解法
我真的太想知道答案了!!
转载自:https://juejin.cn/post/7231940493256998972