手机版

原生JS控制多个滚动条同步跟随滚动效果

时间:2021-09-01 来源:互联网 编辑:宝哥软件园 浏览:

在一些支持用markdown写文章的网站中,后台写作页面一般支持markdown即时预览,即整个页面分为两部分,左边部分是你输入的markdown文本,右边部分立即输出对应的预览页面。例如,以下是CSDN后台写作页面的降价即时预览效果:

本文没有说明如何从0开始达到这个效果(很有可能以后会发表一篇单篇文章)。抛开其他,只看页面主体中的左右容器元素,即标记输入框元素和预览显示框元素。

本文讨论了当两个容器元素的内容超过容器高度时,即当滚动框出现时,如何使一个容器元素滚动。

DOM结构

因为它与滚动条相关,所以首先想到js中控制滚动条高度的一个属性:scrollTop。只要能控制这个属性的值,自然就能控制滚动条的滚动。

具有以下DOM结构:

div id=' container ' div class=' left '/div class=' right '/div/div其中。左元素是左输入框容器元素。右元素是右显示框容器元素。容器是它们共同的父元素。

因为需要溢出滚动,所以需要设置对应的样式(只有按键样式,不是全部):

# container { display: flexborder: 1px实心# bbb}.向左,向右。右{ flex : 1;高度: 100%;word-wrap:断字;溢出-y:滚动;}然后将足够的内容放入。向左和向右。右元素使滚动条出现在它们上面,这是以下效果:

样式是一个粗略的想法,所以可以在这些DOM上执行一系列操作。

首次尝试

一般的思路是监听两个容器元素的滚动事件,当一个元素滚动时,获取这个元素的scrollTop属性的值,并将这个值设置为另一个滚动元素的scrollTop值。

例如:

var l=document.queryselector('的效果。左')var r=document.queryselector('。右)l.addeventlistener ('scroll ',function(){ r . scroll top=l . scroll top })如下:

看起来很好,但现在我希望右跟左,左跟右,所以我添加了以下代码:

Addeventlistener ('scroll ',function(){ r . scroll top=l . scroll top })看起来很不错,但是,没有这么简单的事情。

这时再用鼠标滚轮滚动时,发现滚动有点困难。两个容器元素的滚动好像被什么东西阻碍了,滚动起来很困难。

仔细分析后,原因很简单。当您向左滚动时,它会触发左侧滚动事件,因此右侧会跟随滚动,但同时,右侧也会跟随滚动,因此它也会触发右侧滚动,因此左侧也会跟随右侧滚动.然后进入类似于相互触发的情况,很难滚动。

解决滚动事件同时触发的问题

解决上述问题,暂时有两种方案。

用鼠标滚轮事件替换滚动事件

由于滚动事件不仅会由鼠标主动滚动触发,还会通过改变容器元素的scrollTop来触发,而元素的主动滚动实际上是由mousewheel触发的,因此滚动事件可以由对鼠标滚动敏感的事件代替,而不是元素滚动:“mousewheel”,所以上面的监控代码变成:

Addeventlistener ('mousewheel ',function(){ r . scroll top=l . scroll top })r . addevent listener(' mouse wheel ',function(){ l . scroll top=r . scroll top })具有以下效果:

看似有用,其实有两个问题。

当其中一个容器元素滚动时,另一个容器元素也随之滚动,但滚动不流畅,高度有明显的瞬间反弹

我在网上搜了一圈,找不到关于车轮事件滚动频率的相关内容。我猜这可能是这次活动的一个特点

每次鼠标滚动,基本不是以1px为单位,最小单位比滚动事件小很多。我用鼠标在chrome浏览器上滚动,每次滚动的距离正好是100px。不同的鼠标或浏览器应该有不同的值。事实上,滚轮事件真正监控的是鼠标滚轮滑过齿轮卡住的事件,这可以解释它为什么会反弹。

一般来说,鼠标滚轮每滚动一个档位点,就能听到一个滚轮事件。从开始到结束,鼠标主动滚动的元素已经滚动了100px,所以跟随滚动的另一个容器元素瞬间跳转了100px。

上面的滚动事件之所以不会导致后面的滚动元素瞬间弹起,是因为后面的滚动元素的值不会有100px那么大的跨度,可能每次scrollTop改变的时候也不会有1px那么小,但是因为它的触发频率高,滚动跨度小,至少在视觉上是平滑的。

Wheel只是监听鼠标滚轮事件,但如果用鼠标拖动滚动条,则不会触发此事件,其他容器元素也不会跟随滚动

其实这个很容易解决,用鼠标拖动滚动条绝对可以触发滚动事件。在这种情况下,您可以很容易地确定拖动的滚动条属于哪个容器元素,只处理这个容器的滚动事件,而不处理滚动容器后面的其他滚动事件。

车轮事件的兼容性问题

wheel事件是DOM Level3的标准事件,但是除了这个事件之外,还有很多非标准事件,不同的浏览器内核使用不同的标准,所以可能需要根据情况进行兼容,具体就是MDN MouseWheelEvent

实时判断

如果你受不了轮子的弹跳和各种兼容性,其实还有另外一条路要走,依然是滚动事件,只是需要做一些额外的工作。

滚动事件的问题在于,不判断当前哪个容器元素被主动滚动,只要确定了被主动滚动的容器元素,就很容易做到。例如,在上述滚轮事件中,可以通过用鼠标拖动滚动条来使用滚动事件的原因是,很容易确定哪个容器元素当前正在活动滚动。

因此,问题的关键在于如何判断当前正在主动滚动的容器元素。只要这个问题解决了,剩下的就好办了。

无论是鼠标滚轮滚动还是鼠标按在滚动条上拖动滚动条滚动,都会触发滚动事件,此时,在坐标系的Z轴上,鼠标的坐标必须在滚动容器元素占据的区域内,也就是说,在Z轴上,鼠标必须悬浮在滚动容器元素的上方或上方。

当鼠标在屏幕上移动时,可以获得鼠标的当前坐标。

ClientX和clientY是当前鼠标相对于视口的坐标。可以认为,只要这个坐标在某个滚动容器的范围内,这个容器元素就被认为是活动的滚动容器元素,使用getBoundingClientRect就可以得到容器元素的坐标范围。

下面是将鼠标移动到。左侧元素:

如果(e . client XL . left e . client XL . right . client yl . top){//输入。left element}确实可以,但是考虑到两个滚动的容器元素几乎占据了整个屏幕区域,mousemove要监控的区域有点大,可能对性能要求比较高,所以可以用mouseover事件来代替,只需要监控鼠标是否进入了某一个即可。

Addeventlistener('鼠标悬停',function () {//enter。左滚动容器元素})当确定鼠标主动滚动哪个容器元素时,只需要处理这个容器的滚动事件,滚动容器之后的其他滚动事件不需要处理。

嗯,效果很好,表现也很好,完美,可以收工了~

按比例滚动

上面的例子都是两个滚动容器元件的内容完全一致时的效果。如果两个滚动容器元件的内容物不同怎么办?

这是以下效果:

可以看出,由于两个滚动容器元素的内容高度不同,最大scrollTop也不同。当滚动顶端值较小的元素之一滚动到底部时,另一个元素仍然停留在一半,或者当滚动顶端值较大的元素之一滚动到一半时,另一个元素已经滚动到底部。

这种情况很常见。例如,当您使用标记向下书写时,编辑模式下一级标题标记#所占的高度通常小于预览模式所占的高度,这导致左右两侧的滚动高度不一致。

因此,如果考虑到这种情况,就不像为两个滚动容器元素设置scrollTop值那么简单了。

滚动容器内容的高度虽然不能固定,但有一点是肯定的:滚动条的最大滚动高度,或者scrollTop的值,肯定和滚动容器内容的高度以及滚动容器本身的高度有关。

因为您需要知道滚动容器内容的高度,并且有滚动条,所以您需要向这个容器元素添加子元素。子元素的高度不受限制,即滚动容器内容的高度是固定的,溢出滚动就足够了。

div id=' container ' div class=' left ' div class=' child '/div/div class=' right ' div class=' child '/div/div/div结构示例如下:

通过我的观察推断和实践验证,它们之间的关系已经确定,这很简单,就是最基本的加减运算:

滚动条的最大滚动顶部最大值=滚动容器内容的高度(即子元素高度ch)-滚动容器本身的高度(即容器元素高度ph),即

也就是说,如果已经确定了滚动容器内容的高度(即子元素高度ch)和滚动容器本身的高度(即容器元素高度ph),那么就可以确定滚动条的最大scrollTop,这两个高度值基本都是可用的,所以就可以得到scrollTop。

因此,如果你想让两个滚动元素容器等比例上下滚动,即一个元素可以滚动到头部或底部,另一个元素也可以相应地滚动到头部和底部,你只需要得到两个滚动容器元素之间scrollTop最大值的刻度。

确定比例后,在实时滚动时,只需要得到主动滚动的容器元素的scrollTop1,就可以得到滚动后另一个容器元素对应的scrollTop2:

思路清晰,写代码很容易,效果如下:

很顺滑~

摘要

上述要求已经实现,在实践中可能需要根据实际情况进行一些修改。比如你写了一个markdown的在线编辑预览页面,需要根据输入内容的高度实时更新比例值,但是主体已经定了,做小改动并不难。

此外,本文不仅针对两个滚动容器元件的后续滚动,还可以进行扩展。根据本文的思想,可以实现更多的元素间跟随滚动。为了便于解释,本文只关注两个要素。

摘要

以上是边肖介绍的原JS,控制多个滚动条同步跟随滚动效果。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。谢谢您的支持!

版权声明:原生JS控制多个滚动条同步跟随滚动效果是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。