ChatGPT解决这个技术问题 Extra ChatGPT

如何同步两个 div 的滚动位置?

我希望有 2 个 div 大小为特定宽度(即 500 像素)。一个在另一个之上,水平对齐。

顶部框应隐藏其滚动条,底部应显示滚动条,当用户滚动时,我希望顶部框的偏移量更改为底部框的值。因此,当底部 DIV 水平滚动时,顶部 DIV 似乎也在同步滚动。

如果它使过程更容易,我很高兴在 Jquery 中执行此操作。


J
Jasper
$('#bottom').on('scroll', function () {
    $('#top').scrollTop($(this).scrollTop());
});

在这里,我们尽其所能使用 .scrollTop(),从带有滚动条的元素中获取 scrollTop 值,并为其他元素设置 scrollTop 以同步它们的滚动位置:http://api.jquery.com/scrollTop

这假定底部元素的 ID 为 bottom,顶部元素的 ID 为 top

您可以使用 CSS 隐藏 top 元素的滚动条:

#top {
    overflow : hidden;
}

这是一个演示:http://jsfiddle.net/sgcer/1884/

我想我从来没有真正有理由这样做,但它看起来很酷。


好的很好的例子(谢谢!)。您能否偶然提供一个类似的示例,但使用 Jquery Scroll Left 使其水平滚动?
@约瑟夫。 :),您是否尝试过将两个实例的 scrollTop 替换为 scrollLeft
@约瑟夫。这是一个更新的 JSFiddle,它演示了使用 scrollLeft 而不是 scrollTopjsfiddle.net/sgcer/1
贾斯珀这里的好例子!
在演示小提琴中,#bottomoverflow 实际上应该是 overflow-y,以避免在带有滚动控件的 div 底部获得 x-scrollbar。
A
Artem Kachanovskyi

我知道这是一个旧线程,但也许这会对某人有所帮助。如果您需要双向同步滚动,仅处理两个容器的滚动事件并设置滚动值是不够的,因为滚动事件进入循环并且滚动不平滑(尝试垂直滚动鼠标滚轮 Hightom 给出的示例)。

这是一个如何检查是否已经在同步滚动的示例:

var isSyncingLeftScroll = false; var isSyncingRightScroll = false; var leftDiv = document.getElementById('left'); var rightDiv = document.getElementById('right'); leftDiv.onscroll = function() { if (!isSyncingLeftScroll) { isSyncingRightScroll = true; rightDiv.scrollTop = this.scrollTop; } isSyncingLeftScroll = false; } rightDiv.onscroll = function() { if (!isSyncingRightScroll) { isSyncingLeftScroll = true; leftDiv.scrollTop = this.scrollTop; } isSyncingRightScroll = false; } .container { 宽度:200px;高度:500px;溢出-y:自动; } .leftContainer { 浮动:左; } .rightContainer { 浮动:对; }

但是为了让你看到所有这些错误是由那些指责快乐和赞美痛苦的人造成的,我将打开整个事情并解释一下那个 真理 的 发现 者 , 就像 它 是 幸福 生活 的 建筑师 .因为没有人鄙视、憎恨或逃避快乐本身,因为它是快乐,而是因为那些不懂得如何用理性去追求快乐的人会遭受巨大的痛苦;从来没有这样的时候,他通过劳动和疼痛。对于最细微的细节,我们中的哪一个人进行任何费力的体育锻炼,除非是为了从中获得一些好处?但是,谁能正确地责怪那些想要享受那种没有任何不适的快乐的人,或者一个避免痛苦但不会带来任何快乐的人呢?但事实上,我们都以正当的仇恨来指责和煽动那些应得的人,他们被当前快乐的奉承软化和腐化,被贪婪蒙蔽了双眼,没有准备好他们将要经历的痛苦和麻烦。事实上,这些事物之间的区别是容易和权宜的。 For in our free time, when the option of choosing is open to us, and nothing hinders us, the less we can do that which pleases us most, all pleasure must be assumed, all pain rejected.但在某些时候,无论是因为职责,还是因为事情的需要,经常会发生既要拒绝快乐,又不要拒绝麻烦的情况。因此,聪明人必须选择这些东西,以便通过拒绝更大的快乐他可以获得其他快乐,或者通过忍受痛苦他可以拒绝它们。

这是fiddle


完美...效果很好!谢谢你。
太好了谢谢!!
一个纯 JavaScript 解决方案。谢谢你。
我对水平滚动应用了相同的逻辑。效果很好。谢谢!
H
Hightom

我一直在寻找双向解决方案,感谢大家,您的贡献帮助我做到了这一点:

$('#cells').on('scroll', function () {
$('#hours').scrollTop($(this).scrollTop());
$('#days').scrollLeft($(this).scrollLeft());});

参见 JSFiddle:https://jsfiddle.net/sgcer/1274/

希望有一天它对某人有所帮助:-)


R
Robert McLaws

好的,所以我评估了这里提供的所有选项,它们都有一种或另一种形式的限制:

接受的答案存在使用鼠标滚轮的已知问题。

下一个最高赞成票没有滚轮问题,但仅适用于两个已知元素。如果您需要更多元素,则它是不可扩展的。

唯一显示出希望的解决方案是 Lacho 的,但代码中存在已知的元素引用,这些引用未包含在代码段中。从好的方面来说,它具有性能所需的结构,而且它在 TypeScript 中。

我利用它创建了一个可重用的版本,它可以处理无限数量的元素,并且不需要 JQuery。

function scrollSync(selector) {
  let active = null;
  document.querySelectorAll(selector).forEach(function(element) {
    element.addEventListener("mouseenter", function(e) {
      active = e.target;
    });

    element.addEventListener("scroll", function(e) {
      if (e.target !== active) return;

      document.querySelectorAll(selector).forEach(function(target) {
        if (active === target) return;

        target.scrollTop = active.scrollTop;
        target.scrollLeft = active.scrollLeft;
      });
    });
  });
}

//RWM: Call the function on the elements you need synced.
scrollSync(".scrollSync");

您可以在此处查看 JSFiddle:http://jsfiddle.net/gLa2ndur/3。您可以看到它同时使用了水平和垂直滚动示例。

唯一已知的限制是它可能不适用于不同大小的 div。如果您的用例认为有必要(我的没有),我相信有人可以将 Andrew's work 纳入其中。

我希望这对某人有帮助!


它可能会使用一些美化,但这里是相对/绝对版本:jsfiddle.net/2wdbcfjz/37
L
LachoTomov

防止这种循环问题并实现平滑滚动的另一种解决方案。这确保只有焦点元素获得滚动事件。

let activePre: HTMLPreElement = null;
document.querySelectorAll(".scrollable-pre").forEach(function(pre: HTMLPreElement) {
    pre.addEventListener("mouseenter", function(e: MouseEvent) {
        let pre = e.target as HTMLPreElement;
        activePre = pre;
    });

    pre.addEventListener("scroll", function(e: MouseEvent) {
        let pre = e.target as HTMLPreElement;

        if (activePre !== pre) {
            return;
        }

        if (pre !== versionBasePre) {
            versionBasePre.scrollTop = pre.scrollTop;
            versionBasePre.scrollLeft = pre.scrollLeft;
        }

        if (pre !== versionCurrentPre) {
            versionCurrentPre.scrollTop = pre.scrollTop;
            versionCurrentPre.scrollLeft = pre.scrollLeft;
        }

    });
});

谢谢你!我在这里使用它作为我的答案的基础,它可以让您同步无限数量的可滚动元素:stackoverflow.com/a/63864273/403765
A
Atanas Sarafov

感谢上面的答案,我制作了一个适合我的混合解决方案:

var isLeftScrollTopCalled = false;
$('#leftElement').scroll(function (e) {
    if (isRightScrollTopCalled) {
        return isRightScrollTopCalled = false;
    }

    $('#rightElement').scrollTop($(this).scrollTop());
    isLeftScrollTopCalled = true;
});

var isRightScrollTopCalled = false;
$('#rightElement').scroll(function (e) {
    if (isLeftScrollTopCalled) {
        return isLeftScrollTopCalled = false;
    }

    $('#leftElement').scrollTop($(this).scrollTop());
    isRightScrollTopCalled = true;
});

A
Andrew Nguyen

我注意到他的问题已经很老了,但我认为我可以留下一个比使用计时器更好的 jQuery 实现。在这里,我使用两个事件侦听器,就像以前使用的解决方案一样,但是,这将使用比例/百分比来同步两个不同大小的 div 框的滚动。您可以应用相同的知识来获取滚动条到 Vanilla JS 解决方案的位置。这将使两个 div 之间的滚动更加平滑。

/** Scroll sync between editor and preview **/
// Locks so that only one pane is in control of scroll sync
var eScroll = false;
var pScroll = false;
// Set the listener to scroll
this.edit.on('scroll', function() {
    if(eScroll) { // Lock the editor pane
        eScroll = false;
        return;
    }
    pScroll = true; // Enable the preview scroll

    // Set elements to variables
    let current = self.edit.get(0);
    let other = self.preview.get(0);

    // Calculate the position of scroll position based on percentage
    let percentage = current.scrollTop / (current.scrollHeight - current.offsetHeight);

    // Set the scroll position on the other pane
    other.scrollTop = percentage * (other.scrollHeight - other.offsetHeight);
});
this.preview.on('scroll', function() {
    if(pScroll) { // Lock the preview pane
        pScroll = false;
        return;
    }
    eScroll = true; // Enable the editor scroll

    // Set elements to variables
    let current = self.preview.get(0);
    let other = self.edit.get(0);

    // Calculate the position of scroll position based on percentage
    let percentage = current.scrollTop / (current.scrollHeight - current.offsetHeight);

    // Set the scroll position on the other pane
    other.scrollTop = percentage * (other.scrollHeight - other.offsetHeight);

});