起因,过程,结果
起因,自己遇到的问题
有一天公司项目遇到 el-tree 的过滤数据不正确现象,之前过滤数据是没问题的,最近产生的问题,我先查看项目代码,发现代码并没有改动,
再深入排查之后,发现是 element-plus 的版本问题,原版本 2.9.0,升级到 2.9.7 后产生的 bug,对照了一下源码,
发现原来是 el-tree 的源码发生了修改,然后在 element 的 issues 中开始查找有没有人提出问题,找到了一个issues,
然后在下面评论了一下,没过几天,发现有人解决了这个问题,查看解决代码以后发现只是加了一句很简单的 await,想到原来有些问题并不是很难,只不过我没有想过去处理,早知道我来解决好了哈哈
过程,如何找到bug出现的原因并且修复bug
1.找到bug
于是我就开始在 issues 中查看别人提出的 bug,找到一个关于table 的 bug,
描述是这样的,el-table-column type 为"selection"加上 fixed 以后,只能放在表格中的第一项才能显示,没有 fixed 的时候,任何位置都可以展示,
我根据这些关键信息,去看 element-plus 的源码,找了许久才终于找到问题的出现点,就是在 updateColumns 方法中,拿 columns.value[0]来判断是否为 selection,
如果是,则判断他的 fixed 属性是否为 left 或者 true,以及是否有固定列并且 selection 列的 fixed 属性不为 right,bug 的出现就是这里导致了.
下面为原始代码:
// 更新列
const updateColumns = () => {
_columns.value.forEach((column) => {
updateChildFixed(column)
})
fixedColumns.value = _columns.value.filter(
(column) =>
column.type !== 'selection' && [true, 'left'].includes(column.fixed)
)
let selectColFixLeft
if (_columns.value?.[0]?.type === 'selection') {
const selectColumn = _columns.value[0]
selectColFixLeft =
[true, 'left'].includes(selectColumn.fixed) ||
(fixedColumns.value.length && selectColumn.fixed !== 'right')
if (selectColFixLeft) {
fixedColumns.value.unshift(selectColumn)
}
}
rightFixedColumns.value = _columns.value.filter(
(column) => column.fixed === 'right'
)
const notFixedColumns = _columns.value.filter(
(column) =>
(selectColFixLeft ? column.type !== 'selection' : true) && !column.fixed
)
originColumns.value = []
.concat(fixedColumns.value)
.concat(notFixedColumns)
.concat(rightFixedColumns.value)
const leafColumns = doFlattenColumns(notFixedColumns)
const fixedLeafColumns = doFlattenColumns(fixedColumns.value)
const rightFixedLeafColumns = doFlattenColumns(rightFixedColumns.value)
leafColumnsLength.value = leafColumns.length
fixedLeafColumnsLength.value = fixedLeafColumns.length
rightFixedLeafColumnsLength.value = rightFixedLeafColumns.length
columns.value = []
.concat(fixedLeafColumns)
.concat(leafColumns)
.concat(rightFixedLeafColumns)
isComplex.value =
fixedColumns.value.length > 0 || rightFixedColumns.value.length > 0
}
2.第一版修改
理解完代码以后,就开始着手修复问题,我想的是先把select列给提出来,然后判断有没有select列,再判断是放在左边还是右边.
第一版修改代码如下:

3.提交代码的问题
因为是第一次在github上修改开源代码,我仔细的看了一下提交代码的规范流程,但是在提交代码的时候报没有权限,
我的做法是这样的,在element-plus上clone一份到本地,创建一个新分支"fix#xxx",然后提交,
一直提交不上去以后我就开始在网上找办法,发现网上说的也是一样的做法,
还好之前混迹掘金也加入了一个"varletjs"开源项目微信社群,我就在群里请教了一下大佬们.

我就是缺少了fork这一步,于是我先fork,然后在开新分支,再提交代码,提交pr就静等审查了
4.第二版修改
github中有大佬指出了我第一版代码的问题:
我把selection取出来以后,要么固定左边要么固定右边,selection列如果不固定的时候,就会把他给追加在不固定列的最后一列.

我意识到问题以后继续修改,修改后的代码:
先找到非selection的其它左侧固定列,在找到固定列的selection,再判断selection是否该追加到左侧固定列中,当时写的时候没发现写的这么粗糙,
现在看起来第二版写的很差.

5.关于test案例
第二版提交以后,疑似element-plus审查人员(btea大佬)跟我说让我提供一个test案例,然后github的机器人再下面评论了一个playground地址,
我当时理解的是在element-plus的playground写一个测试代码来验证,写完以后就提交了.
6.与审查人员的交流
btea大佬提出了个建议,selection只保留一列就可以了

我提出了我的异议,我觉得此次修改bug的目的是为了解决selection列不在第一个就无法显示的问题,而不是优化selection应该显示几列,
而且element-plus之前是可以显示多列的,其它UI库例如ant-design-vue也是可以显示多列的,这应该是由用户来选择显示几列,而不是开发者来限制.

7.修改测试用例
btea大佬说到因为我的修改导致测试用例不通过,这个时候我还不懂什么是测试用例,因为之前没有接触过.
(我才意识到大佬上面说让我添加一个test用例,我理解成playground代码演示了......)

我按照btea大佬说的本地执行pnpm test以后,发现报错了,看了一下报错的地方

然后找到该文件,找到了报错的地方

上面的测试用例我看不明白,然后我就在掘金上搜索"vue的test用例",
看到了乘风gg大佬写的完全掌握vue全家桶单元测试,看了1-4篇文章,
又回过头来看代码,理解了这段代码以后,我发现这个问题是因为此test案例依赖于之前那版代码的逻辑实现,现我已修改了代码,所以这个test案例也应该修改
初版代码
let selectColFixLeft
if (_columns.value?.[0]?.type === 'selection') {
const selectColumn = _columns.value[0]
selectColFixLeft =
[true, 'left'].includes(selectColumn.fixed) ||
(fixedColumns.value.length && selectColumn.fixed !== 'right')
if (selectColFixLeft) {
fixedColumns.value.unshift(selectColumn)
}
}
于是我直接把test案例中的这段代码给删除,发现果然不报错了,我就把修改后的test案例代码给提交上去了

8.第三版修改:
btea大佬又提出了他的想法,说测试案例没错,我应该兼容测试案例.

此时我真的不知道该如何修改了,我觉得当前测试案例是依赖于之前的逻辑代码,之前的逻辑代码是错误的,我已经修改了,所以我也应该修改测试案例,逻辑没毛病啊,于是我从github中找到了btea大佬的qq,请求添加好友,大佬通过以后我发出了我的疑问,
大佬是这样回答我的:"因为原来的逻辑是默认selection列在第一个,所以导致selection列放在其他位置时没有渲染,我觉得直接把selection列筛选出来,然后走原来的逻辑就可以了".
大佬在github中还给我指出了应该如何修改,我把test案例给还原,然后按照他指出的方案修改,发现又有新的问题,我告诉他以后,他觉得这是合理的,虽然我觉得这个隐藏逻辑不太合理,我不理解为什么要在错误的基础上继续修改,这样怎么修改都还是错误,但是因为这一个bug已经耽误了我很多时间,我有点不想再这个bug上一直纠结了,于是我按照他的修改以后就提交了.


9.第四版修改:
我以为此次bug应该在上面那版提交就结束了,直到大佬又找到了我,跟我聊了一下,跟他交流以后我决定还是按照我想的方式去修改,

改完以后呢,问题又回到了test案例报错,这个时候我跟大佬吐槽:




这个时候我才真正理解了btea大佬的意思.
"这段代码确实有问题,但是这段有问题的代码已经有很多人在用了,用户使用的时候并不觉得是一个问题,可能当成了隐式逻辑使用,如果这一版把这个有问题的代码给修复,可能会导致原来正常使用的用户出现问题",
这时我才意识到element-plus并不是一个小项目,而是很多前端同学在用的UI组件库.
于是我专心的把代码又从头到尾细看了一遍,然后再修改了一遍,最终版代码如下:
我的逻辑是:
先找到左侧固定列(不包含selection列),再找到右侧固定列(不包含selection列),再找到需要固定的selection列(固定的selection列兼容之前如果有固定列并且selection列为第一列,把selection也放在固定列的逻辑),然后再判断固定列需要追加到左侧还是右侧,然后在判断不固定列是否需要显示selection列.

10.第五版修改:
btea大佬审查了代码以后,进行了修改,修改后的代码如下:

我看了一遍,理解到我修改的地方还是有不足,我不应该在修改bug的情况下,去动到原本的代码逻辑.
1.我把selection固定列提取出来,放到最左侧或者最右侧,我理解起来没问题,但是放到最右侧又与原先的代码逻辑不同了.
2.我修改了非固定列是否显示selection列的逻辑,根据是否有selection固定列来判断,原本是根据是否有左侧固定列来判断的.
结果,bug成功修复
最后bug成功修复,我的代码也已经合并到了element-plus仓库当中,
更值得高兴的是我的github主页还多了一个贡献者徽章,
经过这次的 element-plus bug修复,也让我从中学到了很多东西,代码之路还长,希望我能一直学习,一直进步!
