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

时间:2012-02-10 23:31:37

标签: javascript jquery

我希望有两个大小为特定宽度的div(即500px)。一个在另一个之上水平对齐。

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

如果它让这个过程更容易,我很高兴在Jquery中这样做。

7 个答案:

答案 0 :(得分:88)

$('#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/

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

答案 1 :(得分:37)

我知道这是一个旧线程,但也许这会对某人有所帮助。 如果你需要在双向上同步滚动,它不足以只处理两个容器'滚动事件并设置滚动值,因为滚动事件进入循环并且滚动不平滑(尝试通过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 {
  width: 200px;
  height: 500px;
  overflow-y: auto;
}

.leftContainer {
  float: left;
}

.rightContainer {
  float: right;
}

<div id="left" class="container leftContainer">
Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
</div>
<div id="right" class="container rightContainer">
Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
</div>
&#13;
&#13;
&#13;

这是fiddle

答案 2 :(得分:11)

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

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

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

希望有一天能帮助别人: - )

答案 3 :(得分:2)

好的,所以我评估了这里介绍的所有选项,它们都有某种形式或另一种形式的局限性:

  • accepted answer使用鼠标滚轮遇到已知问题。
  • next highest upvote没有滚轮问题,但仅适用于两个已知元素。如果需要更多元素,则无法扩展。
  • 唯一能实现承诺的解决方案是Lacho's,但是代码段中没有包含已知的元素引用。从好的方面来说,它具有性能所需的结构,并且在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并入其中。

我希望这对某人有帮助!

答案 4 :(得分:0)

感谢上面的答案,我提出了一个优先为我工作的混合解决方案:

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;
});

答案 5 :(得分:0)

另一种解决方案,可以防止出现此循环问题并实现平滑滚动。 这样可以确保只有焦点元素才能获得滚动事件。

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;
        }

    });
});

答案 6 :(得分:0)

我注意到他的问题已经很老了,但是我认为我可以留下一个比使用计时器更好的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);

});