从element的一次PR开始

缘起

那天我正刷着B站,主页突然跳出来up程序员小山与Bug的视频,名字叫 el-table固定表头滚动时,表头不跟手抖动的问题,跟着学到了一点调试小技巧,和大家分享下。

1、Ctrl + Shift + p 可以召唤出Chrome的命令

可以在里面方便的禁用js脚本

2、github上的 #数字 可以直接在github上的PR那边直接进入

比如

https://github.com/ElemeFE/element/pull/21863

这里的21863 就是编号

同样在releases 的文档种能找到这行

指的就是这个功能的PR号,非常的方便,看别人源码也不容易大海捞针

3、如何简单排查某行代码是否会影响其他功能,如果测试写的好的话直接跑测试,那如果测试不方便或者看不出来尼,可以看下增加那段代码时候的提示,是否是为了解决bug或者新增的功能或者单纯的是提高性能。

然后来看下这个同步是怎么做的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
syncPostion() {
const { scrollLeft, scrollTop, offsetWidth, scrollWidth } = this.bodyWrapper;
const { headerWrapper, footerWrapper, fixedBodyWrapper, rightFixedBodyWrapper } = this.$refs;
if (headerWrapper) headerWrapper.scrollLeft = scrollLeft;
if (footerWrapper) footerWrapper.scrollLeft = scrollLeft;
if (fixedBodyWrapper) fixedBodyWrapper.scrollTop = scrollTop;
if (rightFixedBodyWrapper) rightFixedBodyWrapper.scrollTop = scrollTop;
const maxScrollLeftPosition = scrollWidth - offsetWidth - 1;
if (scrollLeft >= maxScrollLeftPosition) {
this.scrollPosition = 'right';
} else if (scrollLeft === 0) {
this.scrollPosition = 'left';
} else {
this.scrollPosition = 'middle';
}
},

其实很简单,获取当前的scrollLeft 赋值给另一个 scrollLeft 就完成了,让我们来写个简单的同步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// index.html
<div class="headerWrapper wrapper">
<table>
<colgroup>
<col width="180">
<col width="180">
<col width="200">
<col width="200">
</colgroup>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
</table>

</div>
<div class="bodyWrapper wrapper">
<table>
<colgroup>
<col width="180">
<col width="180">
<col width="200">
<col width="200">
</colgroup>
<tbody>
<tr>
<td>凉风有信</td>
<td>秋月无边</td>
<td>亏我思娇情绪好比度日如年</td>
<td>恨天各一方难与秋娟再相见</td>
</tr>
</tbody>
</table>

</div>

css

1
2
3
4
5
6
7
8
9
10
11
12
.wrapper{
width:300px;
overflow: auto;
}

.wrapper > table{
width:800px;

}
.headerWrapper{
overflow: hidden;
}

下面就是见证奇迹的时刻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function ready() {

const headerWrapper = document.getElementById("headerWrapper");
const bodyWrapper = document.getElementById("bodyWrapper");

bodyWrapper.addEventListener('scroll', function() {
window.requestAnimationFrame(() => {
let top = this.scrollTop
let left = this.scrollLeft
headerWrapper.scrollTo(left, top);
})
})
}

document.addEventListener("DOMContentLoaded", ready);

在线练习链接 https://jsfiddle.net/knightgao/ksbyLfjg/59/

这样就实现了简单的js联动

那更进一步,按照力扣的命名规则,刚刚那题叫联动的话,那下面这题叫联动2

要求是n个互相影响尼,比如给了一排的div,要求拖动其中一个带动所有的进行滚动

1对1 到了 1对 N

原理没变,多了一些要求

  • 避免触发遍历的时候改变自己
  • 避免scroll 事件循环触发

关于循环触发这里补充下

循环触发例子链接 https://jsfiddle.net/knightgao/5L9mkz1t/19/

当test1滚动的时候会设置同步test2的值,如果这时候 test2 scroll 事件 中设置 test1的值,就会导致循环触发,造成不必要的性能浪费

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<div class="headerWrapper wrapper">
<table>
<colgroup>
<col width="400">
<col width="400">
<col width="400">
<col width="400">
</colgroup>
<thead>
<tr>
<th>冲动</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
</table>

</div>
<div class="bodyWrapper wrapper">
<table>
<colgroup>
<col width="400">
<col width="400">
<col width="400">
<col width="400">
</colgroup>
<tbody>
<tr>
<td>那夜我喝醉了拉着你的手</td>
<td>胡乱地说话</td>
<td>只顾着自己心中压抑的想法</td>
<td>狂乱地表达</td>
</tr>
</tbody>
</table>
</div>

<div class="bodyWrapper wrapper">
<table>
<colgroup>
<col width="400">
<col width="400">
<col width="400">
<col width="400">
</colgroup>
<tbody>
<tr>
<td>我迷醉的眼睛已看不清你表情</td>
<td>忘记了你当时会有怎样的反应</td>
<td>我拉着你的手放在我手心</td>
<td>我错误地感觉到你也没有生气</td>
</tr>
</tbody>
</table>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
.wrapper{
width:600px;
overflow: auto;
}

.wrapper > table{
width:2000px;

}
.headerWrapper{
overflow: hidden;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function ready() {

const nodes = document.getElementsByClassName("wrapper");

function initScroller(nodes) {
let max = nodes.length
if (!max || max === 1) return
let limit = 0;
nodes.forEach((ele, index) => {
ele.addEventListener('scroll', function() {
window.requestAnimationFrame(() => {
if (!limit) {
limit = max - 1;
let top = this.scrollTop
let left = this.scrollLeft
for (node of nodes) {
if (node === this) continue;
node.scrollTo(left, top);
}
} else
--limit;
})
}, {
passive: true
});
});
}
initScroller([...nodes]);
}

document.addEventListener("DOMContentLoaded", ready);

从element的一次PR开始
https://blog.devgaoy.cn/2023/12/24/form-Element-PR/
作者
knight.gao
发布于
2023年12月25日
许可协议