从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或者新增的功能或者单纯的是提高性能。

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

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 就完成了,让我们来写个简单的同步

// 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

.wrapper{
 width:300px;
 overflow: auto;
}

.wrapper > table{
 width:800px;
 
}
.headerWrapper{
 overflow: hidden;
}

下面就是见证奇迹的时刻

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的值,就会导致循环触发,造成不必要的性能浪费

<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>
.wrapper{
 width:600px;
 overflow: auto;
}

.wrapper > table{
 width:2000px;
 
}
.headerWrapper{
 overflow: hidden;
}
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);

在线地址 https://jsfiddle.net/knightgao/getb5mpj/24/

同学们下课


已发布

分类

作者:

标签