同页面双窗口跟随滚动

54 阅读3分钟
目录
  • 一、需求场景描述
    • 1.需求分解
  • 二、关键技术点提前知
    • 技术点1:Element.getClientRects()
    • 技术点2:Element.scrollTo()
  • 三、实现思路分析
    • 1.数据初始化处理
    • 2.监听右侧窗口滚动条,以便滚动内容时,实现左侧窗口跟随滚动
  • 四、完整 demo 示例代码

一、需求场景描述

1.需求分解:实现同一页面双窗口,对右侧窗口滚动,实现对应节点跟随。

二、关键技术提前知

技术点1:getClientRects()

1.getClientRects()的作用 : 返回一个指向客户端中每一个盒子的边界矩形的矩形集合。可以获取到盒子到浏览器顶部的距离

技术点2:scrollTo()

2.scrollTo() 方法可以使界面滚动到给定元素的指定坐标位置

1)参数可以为两个分别为x轴 y轴。
2)参数可以为option。top 指定沿Y轴滚动窗口或元素的像素数。left 指定 沿X轴滚动窗口或元素的像素数。behavior : smooth 表示平滑滚动并产生过度效果、instant表示滚动会直接跳转到目标位置,没有过度效果、auto或缺省值表示浏览器会自动选择滚动的过度效果
技术点3:findIndex()

3.findIndex() 方法当返回值为true时,获取当前索引值。返回值为false时,则返回-1

三、实现思路分析

  • 初始化数据:构建两个滚动窗口数据。通过dom方法获取右侧窗口的所有节点(注意:获取到的节点数组为伪数组,无法使用数组方法,可以通过扩展运算符或者Array.from方法构建数组)。getClientRects()方法获取到的是盒子距离顶部的距离。那么当每个盒子当前距离顶部的距离减去第一个盒子距离顶部的距离,就能得到一个以第一个盒子顶部为基线的高度数组。在监听滚动方法中,通过findIndex方法比较滚动的距离在高度数组中的位置获取到索引值,获取到的索引值会是当前可视区域顶部盒子的下一个盒子。因此获取到左侧dom数组(索引值-1)的 getClientRects()- 第一个盒子的getClientRects()到顶部的距离,得到左侧容器当前需要滚动的距离。

四、完整 demo 示例代码

```<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div class="main">
    <div class="scrollwrap1">
 
    </div>
    <div class="scrollwrap2">
 
    </div>
  </div>
</body>
</html>

<script>
  const json=[]
  let array=10;
  for(let i=0;i<array;i++){
    json.push({
      name:`name${i}`,
      content:`content${i}`
    })
  }
  const scroll1=document.querySelector('.scrollwrap1')
  const scroll2=document.querySelector('.scrollwrap2')
  for(let i=0;i<json.length;i++){
    const div=document.createElement('div')
    div.className='row'
    div.innerHTML=`${json[i].name}${json[i].content}`;
    scroll1.appendChild(div)
  }
  for(let i=0;i<json.length;i++){
    const div=document.createElement('div')
    div.className='row'
    div.innerHTML=`${json[i].name}${json[i].content}`;
    scroll2.appendChild(div)
  }
  const row1=scroll1.querySelectorAll('.row')
  const row2=scroll2.querySelectorAll('.row')
  scroll2.onscroll=function(){
    let listHeight=[]
    const firstNode=row2[0].getClientRects()[0].top
    Array.from(row2).forEach(item=>{ 
      listHeight.push(item.getClientRects()[0].top - firstNode)
    })
    let flag = listHeight.findIndex((item) => {
      return item >= scroll2.scrollTop;
    });
    if(flag==0){
      flag=1
    }
    let rowScroll=row1[flag-1].getClientRects()[0].top-row1[0].getClientRects()[0].top
    scroll1.scrollTo(0,rowScroll)
  }
</script>

<style>
  .main{
    display: flex;
    margin-top:100px ;
  }
  .scrollwrap1{
    height: 400px;
    overflow: auto;
  }
  .scrollwrap2{
    height: 400px;
    overflow: auto;
  }
  .row{
    height: 200px;
    width: 500px;
    background: rgba(0, 0, 0, 0.5);
    margin:10px 10px ;
    display: flex;
    justify-content: center;
    align-items: center;
  }
</style>