全部
常见问题
产品动态
精选推荐

Web 实现多组件同步滚动

管理 管理 编辑 删除

前言

在日常业务开发中,我们有时会遇到多个组件需要同步滚动的场景;例如在某个页面中存在多个相关的数据表格,用户在滚动其中一个表格时,其他表格也同步滚动保证数据行的对齐;这个功能在数据看板、仪表盘等多种场景下都很常见。

实现这种功能并非难事,主要思路为监听各个组件的滚动事件,当某个组件主动滚动后将自身的滚动状态同步给其他组件;但这种实现方式背后存在严重的隐患:当某个组件接收到来自其他组件的主动滚动信息,并据此对自身的滚动状态加以同步后,该组件会被动触发滚动事件,并将自身的滚动信息传递给主动滚动组件;在这种情况下,极易造成死循环,并在页面上的表现为组件不停“抽搐”。

思路

要解决这个问题,我们需要理清思路;我们假设当前存在 A 和 B 两个可滚动组件需要进行信息同步,按照上述解决方案编写代码后,整个事件的触发流程如下:

A 主动滚动 -> B 同步 A 的滚动信息 -> A 同步 B 的滚动信息 -> A 主动滚动 -> 无限循环

而理想状态下整个事件的触发流程如下:

A 主动滚动 -> B 同步 A 的滚动信息 -> A 主动滚动 -> B 同步 A 的滚动信息

两者中的区别在于,理想状态下被动滚动的组件不会反复触发滚动事件造成主动组件的滚动。要解决这个问题,我们可以通过在滚动事件中对引起滚动的来源进行区分,从而判断是否要进行滚动信息同步。

Coding

首先编写组件对应的滚动处理程序,当某个组件主动滚动时,scrollPart 为空,则将 scrollPart 设置为当前组件名称;而主动滚动的组件再次触发滚动时,将会同步滚动信息给其他组件,此时其他组件会被动触发滚动事件;由于此前已将 scrollPart 设置为主动滚动事件的组件名称,因此其他组件被动触发滚动事件后会将 scrollPart 置空。

在这种情况下,即使主动滚动的组件被其他组件触发被动滚动,也不会再次进行同步。

type ScrollPart = "compA" | "compB";
let scrollPart: ScrollPart; // 触发原始滚动的组件名称

// 根据组件名称生成组件滚动事件的回调处理程序
const scrollCallbackFactory = (key: ScrollPart) => {
    return () => {
        if (!scrollPart) {
            scrollPart = key;
        } else if (scrollPart === key) {
            syncScrollState();
        } else {
            scrollPart = undefined;
        }
    }
}

接下来需要添加事件监听程序和事件信息同步程序。

const compA = document.querySelector("#compA");
const compB = document.querySelector("#compB");

compA.addEventListener("scroll", scrollCallbackFactory("compA"));
compA.addEventListener("scroll", scrollCallbackFactory("compB"));

function syncScrollState() {
    switch (scrollPart) {
        case "compA":
            compB.scrollTop = compA.scrollTop;
            break;
        case "compB":
            compA.scrollTop = compB.scrollTop;
            break;
    }
}

这种处理组件同步的方法是可扩展的,支持横向、纵向滚动以及多个组件滚动,只需给对应组件添加事件监听,并在 syncScrollState 函数里按照对应的组件同步滚动信息即可。

请登录后查看

plz 最后编辑于2025-02-26 11:45:54

快捷回复
回复
回复
回复({{post_count}}) {{!is_user ? '我的回复' :'全部回复'}}
排序 默认正序 回复倒序 点赞倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level }}

作者 管理员 企业

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推荐': '推荐'}}
{{item.is_suggest == 1? '取消推荐': '推荐'}}
沙发 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暂无简介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
{{item.like_count}}
{{item.showReply ? '取消回复' : '回复'}}
删除
回复
回复

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回复 {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回复' : '回复'}}
删除
回复
回复
查看更多
283
{{like_count}}
{{collect_count}}
添加回复 ({{post_count}})

相关推荐

快速安全登录

使用微信扫码登录
{{item.label}} 加精
{{item.label}} {{item.label}} 板块推荐 常见问题 产品动态 精选推荐 首页头条 首页动态 首页推荐
取 消 确 定
回复
回复
问题:
问题自动获取的帖子内容,不准确时需要手动修改. [获取答案]
答案:
提交
bug 需求 取 消 确 定

微信登录/注册

切换手机号登录

{{ bind_phone ? '绑定手机' : '手机登录'}}

{{codeText}}
切换微信登录/注册
暂不绑定
CRMEB客服

CRMEB咨询热线 咨询热线

400-8888-794

微信扫码咨询

CRMEB开源商城下载 源码下载 CRMEB帮助文档 帮助文档
返回顶部 返回顶部
CRMEB客服