缘起 那天我正刷着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);