2023年6月20日发(作者:)
原⽣JS控制多个滚动条同步跟随滚动效果在⼀些⽀持⽤
markdown 写⽂章的⽹站,后台写作页⾯,⼀般都是⽀持
markdown 即时预览的,也就是将整个页⾯分成两部分,左半部分是你输⼊的
markdown ⽂字,右半部分则即时输出对应的预览页⾯,例如下⾯就是 CSDN 后台写作页⾯的
markdown 即时预览效果:本⽂不是阐述如何从
0 实现这种效果的(后续 很可能 会单出⽂章,),抛开其他,单看页⾯主体中左右两个容器元素,即markdown 输⼊框元素和预览显⽰框元素本⽂要探讨的是,当这两个容器元素的内容都超出了容器⾼度,即都出现了滚动框的时候,如何在其中⼀个容器元素滚动时,让另外⼀个元素也随之滚动。DOM 结构既然是与滚动条有关,那么⾸先想到
js 中控制滚动条⾼度的⼀个属性:
scrollTop ,只要能控制这个属性的值,⾃然也就能控制滚动条的滚动了。对于以下
DOM 结构:
.left 元素是左半部分输⼊框容器元素,
.right 元素是右半部分显⽰框容器元素,
.container 是它们共同的⽗元素。由于需要溢出滚动,所以还需要设置⼀下对应的样式(只是关键样式,⾮全部):#container { display: flex; border: 1px solid #bbb;}.left, .right { flex: 1; height: 100%; word-wrap: break-word; overflow-y: scroll;}再向
.left 和
.right 元素中塞⼊⾜够的内容,让⼆者出现滚动条,就是下⾯这种效果:样式是出来个⼤概了,下⾯就可以在这些
DOM 上进⾏⼀系列的操作了。初次尝试⼤致思路,监听两个容器元素的滚动事件,在其中⼀个元素滚动的时候,获取这个元素的
scrollTop 属性的值,同时将此值设置为另外⼀个滚动元素的
scrollTop 值即可。例如:var l=elector('.left')var r=elector('.right')ntListener('scroll',function(){ Top = Top})效果如下:似乎很不错,但是现在是不仅想让右边跟随左边滚动,还想左边跟随右边滚动,于是再加以下代码:addEventListener('scroll',function(){ Top = Top})看上去很不错,然⽽,哪有那么简单的事情。这个时候你再⽤⿏标滚轮进⾏滚动的时候,却发现滚动得有点吃⼒,两个容器元素的滚动似乎被什么阻碍住了,很难滚动。仔细分析,原因很简单,当你在左边滚动的时候,触发了左边的滚动事件,于是右边跟随滚动,但是与此同时右边的跟随滚动也是滚动,于是也触发了右边的滚动,于是左边也要跟随右边滚动...然后就进⼊了⼀个类似于相互触发的情况,所以就会发现滚动得很吃⼒。解决 scroll 事件同时触发的问题想要解决上述问题,暂时有以下两种⽅案。将 scroll 事件换成 mousewheel 事件由于
scroll 事件不仅会被⿏标主动滚动触发,同时改变容器元素的
scrollTop 也会触发,元素的主动滚动其实就是⿏标滚轮触发的,所以可以将
scroll 事件换成⼀个对⿏标滚动敏感⽽不是元素滚动敏感的事件:'mousewheel',于是上述监听代码变成了:addEventListener('mousewheel',function(){ Top = Top})ntListener('mousewheel',function(){ Top = Top})效果如下:似乎是有点⽤,但是实际上还有两个问题。当滚动其中⼀个容器元素的时候,另外⼀个容器元素虽然也跟着滚动,但滚动得并不流畅,⾼度有明显的瞬间弹跳在⽹上找了⼀圈,没有找到关于
wheel 事件滚动频率相关内容,我推测这可能就是此事件的⼀个
feature⿏标每次滚动基本上都并不是以
1px 为单位的,其最⼩单元远⽐
scroll 事件⼩的多,我⽤我的⿏标在
chrome 浏览器上滚动,每次滚过的距离都恰好是
100px ,不同的⿏标或者浏览器这个数值应该都是不⼀样的,⽽
wheel 事件其实真正监听的是⿏标滚轮滚过⼀个齿轮卡点的事件,这也就能解释为何会出现弹跳的现象了。⼀般来说,⿏标滚轮每滚过⼀个齿轮卡点,就能监听到⼀个
wheel 事件,从开始到结束,被⿏标主动滚动的元素已经滚动了100px ,所以另外⼀个跟随滚动的容器元素也就瞬间跳动了
100px⽽之所以上述
scroll 事件不会让跟随滚动元素出现瞬间弹跳,则是因为跟随滚动元素每次
scrollTop 发⽣变化时,其值不会有100px 那么⼤的跨度,可能也没有⼩到
1px ,但由于其触发频率⾼,滚动跨度⼩,最起码在视觉上就是平滑滚动的了。wheel 只是监听⿏标滚轮事件,但如果是⽤⿏标拖动滚动条,就不会触发此事件,另外的容器元素也就不会跟随滚动了这个其实很好解决,⽤⿏标拖动滚动条肯定是能触发
scroll 事件的,⽽在这种情况下,你肯定能够很轻易地判断出这个被拖动的滚动条是属于哪个容器元素的,只需要处理这个容器的滚动事件,另外⼀个跟随滚动容器的滚动事件不做处理即可。wheel 事件的兼容问题wheel 事件是
DOM Level3 的标准事件,但是除了此事件之外,还有很多⾮标准事件,不同的浏览器内核使⽤不同的标准,所以可能还需要按情况来进⾏兼容,具体可见MDN MouseWheelEvent 实时判断如果你难以忍受
wheel 的弹跳,以及各种兼容,那么其实还有另外的路可以⾛得通,依旧是
scroll 事件,只不过需要做⼀些额外的⼯作。scroll 事件的问题在于,没有判断当前主动滚动的是哪⼀个容器元素,只要确定了主动滚动的容器元素,这事就好办了,例如上述使⽤
wheel 事件中,⽤⿏标拖动滚动条之所以能够使⽤
scroll 事件,就是因为能够很容易地确定当前主动滚动容器元素是哪⼀个。所以,问题的关键在于,如何判断出当前主动滚动的容器元素,只要解决了这个问题,剩下的就很好办了。不论是⿏标滚轮滚动还是⿏标按在滚动条上拖动滚动条滚动,都会触发
scroll 事件,并且这个时候,在坐标系
Z 轴上,⿏标的坐标肯定是位于滚动容器元素所占的⾯积之内的,也就是说,在
Z 轴上,⿏标肯定是悬浮或者位于滚动容器元素之上。⿏标在屏幕上移动的时候,是可以获取到⿏标当前坐标的。其中,
clientX 和
clientY 就是当前⿏标相对于视⼝的坐标,可以认为,只要这个坐标在某个滚动容器的范围内,则认为这个容器元素就是主动滚动容器元素,容器元素的坐标范围可以使⽤
getBoundingClientRect 进⾏获取。下⾯是⿏标移动到
.left 元素中的⽰例代码:if (X> && X< && Y>) { // 进⼊ .left元素中}这样确实是可以的,不过考虑到两个滚动容器元素⼏乎占据了整个屏幕⾯积,所以
mousemove 所要监听的⾯积未免有点⼤,对于性能可能要求较⾼,所以其实可以换成
mouseover 事件,只需要监听⿏标有没有进⼊到某个滚动容器元素即可,也省去上述的坐标判断了。addEventListener('mouseover',function(){ // 进⼊ .left滚动容器元素内})当确定了⿏标主动滚动的容器元素是哪⼀个时,只需要处理这个容器的滚动事件,另外⼀个跟随滚动容器的滚动事件不做处理即可。嗯,效果很不错,性能也很好,
perfect ,可以收⼯喽~按⽐例滚动上述⽰例全部是在两个滚动容器元素的内容⾼度完全⼀致的情况下的效果,如果这两个滚动容器元素的内容⾼度不同呢?那就是下⾯这种效果:可见,由于两个滚动容器元素的内容⾼度不同,所以最⼤的
scrollTop 也就不同,就会出现当其中⼀个
scrollTop 值较⼩的元素滚到底时,另外⼀个元素还停留在⼀半,或者当其中⼀个
scrollTop 值较⼤的元素才滚到⼀半时,另外⼀个元素就已经滚到底了。这种情况很常见,例如你⽤
markdown 写作时,⼀个⼀级标题标记
# 在编辑模式下占⽤的⾼度,⼀般都是⼩于预览模式占⽤的⾼度的,这样就出现了左右两侧滚动⾼度不⼀致的情况。所以,如果将这种情况也考虑进来的话,那么就不能简单地为两个滚动容器元素相互设置
scrollTop 值那么简单。虽然⽆法固定住滚动容器内容的⾼度,但是有⼀点可以确定,滚动条最⼤滚动⾼度,或者说
scrollTop 的值,肯定是与滚动容器内容的⾼度与滚动容器本⾝的⾼度呈⼀定的关系。由于需要知道滚动容器内容的⾼度,还要存在滚动条,所以需要给此容器元素加个⼦元素,⼦元素⾼度不限,就是滚动容器内容的⾼度,容器⾼度固定,溢出滚动即可。
scrollTop ),⽽这两个⾼度值基本上都是可以获取到的,所以就能得到
scrollTop因此,想要让两个滚动元素容器等⽐例上下滚动,即其中⼀个元素滚到头或者滚到底,另外⼀个元素也能对应滚到头和滚到底,那么只要得到这两个滚动容器元素之间的
scrollTop 最⼤值的⽐例(
scale )就⾏了。确定了
scale 之后,实时滚动时,只需要获取主动滚动容器元素的
scrollTop1 ,就能得到另外⼀个跟随滚动的容器元素对应的scrollTop2 :思路弄清晰了,写代码就是很容易的事情了,效果如下:很顺滑~⼩结上述本上已经实现了需求,可能在实践过程中还需要根据实际情况来进⾏⼀定的修改,例如如果你编写⼀个
markdown 的在线编辑和预览页⾯,就需要根据输⼊内容的⾼度实时更新
scale 值,不过主体已经搞定,⼩修⼩改就没什么难度了。另外,本⽂所述不仅是针对两个滚动容器元素的跟随滚动,同时也可扩展开来,更多的元素间的跟随滚动都是可以根据本⽂思路来实现的,本⽂只是为了⽅便讲解⽽具体到了两个元素上。总结以上所述是⼩编给⼤家介绍的原⽣JS控制多个滚动条同步跟随滚动效果,希望对⼤家有所帮助,如果⼤家有任何疑问请给我留⾔,⼩编会及时回复⼤家的。在此也⾮常感谢⼤家对的⽀持!
2023年6月20日发(作者:)
原⽣JS控制多个滚动条同步跟随滚动效果在⼀些⽀持⽤
markdown 写⽂章的⽹站,后台写作页⾯,⼀般都是⽀持
markdown 即时预览的,也就是将整个页⾯分成两部分,左半部分是你输⼊的
markdown ⽂字,右半部分则即时输出对应的预览页⾯,例如下⾯就是 CSDN 后台写作页⾯的
markdown 即时预览效果:本⽂不是阐述如何从
0 实现这种效果的(后续 很可能 会单出⽂章,),抛开其他,单看页⾯主体中左右两个容器元素,即markdown 输⼊框元素和预览显⽰框元素本⽂要探讨的是,当这两个容器元素的内容都超出了容器⾼度,即都出现了滚动框的时候,如何在其中⼀个容器元素滚动时,让另外⼀个元素也随之滚动。DOM 结构既然是与滚动条有关,那么⾸先想到
js 中控制滚动条⾼度的⼀个属性:
scrollTop ,只要能控制这个属性的值,⾃然也就能控制滚动条的滚动了。对于以下
DOM 结构:
.left 元素是左半部分输⼊框容器元素,
.right 元素是右半部分显⽰框容器元素,
.container 是它们共同的⽗元素。由于需要溢出滚动,所以还需要设置⼀下对应的样式(只是关键样式,⾮全部):#container { display: flex; border: 1px solid #bbb;}.left, .right { flex: 1; height: 100%; word-wrap: break-word; overflow-y: scroll;}再向
.left 和
.right 元素中塞⼊⾜够的内容,让⼆者出现滚动条,就是下⾯这种效果:样式是出来个⼤概了,下⾯就可以在这些
DOM 上进⾏⼀系列的操作了。初次尝试⼤致思路,监听两个容器元素的滚动事件,在其中⼀个元素滚动的时候,获取这个元素的
scrollTop 属性的值,同时将此值设置为另外⼀个滚动元素的
scrollTop 值即可。例如:var l=elector('.left')var r=elector('.right')ntListener('scroll',function(){ Top = Top})效果如下:似乎很不错,但是现在是不仅想让右边跟随左边滚动,还想左边跟随右边滚动,于是再加以下代码:addEventListener('scroll',function(){ Top = Top})看上去很不错,然⽽,哪有那么简单的事情。这个时候你再⽤⿏标滚轮进⾏滚动的时候,却发现滚动得有点吃⼒,两个容器元素的滚动似乎被什么阻碍住了,很难滚动。仔细分析,原因很简单,当你在左边滚动的时候,触发了左边的滚动事件,于是右边跟随滚动,但是与此同时右边的跟随滚动也是滚动,于是也触发了右边的滚动,于是左边也要跟随右边滚动...然后就进⼊了⼀个类似于相互触发的情况,所以就会发现滚动得很吃⼒。解决 scroll 事件同时触发的问题想要解决上述问题,暂时有以下两种⽅案。将 scroll 事件换成 mousewheel 事件由于
scroll 事件不仅会被⿏标主动滚动触发,同时改变容器元素的
scrollTop 也会触发,元素的主动滚动其实就是⿏标滚轮触发的,所以可以将
scroll 事件换成⼀个对⿏标滚动敏感⽽不是元素滚动敏感的事件:'mousewheel',于是上述监听代码变成了:addEventListener('mousewheel',function(){ Top = Top})ntListener('mousewheel',function(){ Top = Top})效果如下:似乎是有点⽤,但是实际上还有两个问题。当滚动其中⼀个容器元素的时候,另外⼀个容器元素虽然也跟着滚动,但滚动得并不流畅,⾼度有明显的瞬间弹跳在⽹上找了⼀圈,没有找到关于
wheel 事件滚动频率相关内容,我推测这可能就是此事件的⼀个
feature⿏标每次滚动基本上都并不是以
1px 为单位的,其最⼩单元远⽐
scroll 事件⼩的多,我⽤我的⿏标在
chrome 浏览器上滚动,每次滚过的距离都恰好是
100px ,不同的⿏标或者浏览器这个数值应该都是不⼀样的,⽽
wheel 事件其实真正监听的是⿏标滚轮滚过⼀个齿轮卡点的事件,这也就能解释为何会出现弹跳的现象了。⼀般来说,⿏标滚轮每滚过⼀个齿轮卡点,就能监听到⼀个
wheel 事件,从开始到结束,被⿏标主动滚动的元素已经滚动了100px ,所以另外⼀个跟随滚动的容器元素也就瞬间跳动了
100px⽽之所以上述
scroll 事件不会让跟随滚动元素出现瞬间弹跳,则是因为跟随滚动元素每次
scrollTop 发⽣变化时,其值不会有100px 那么⼤的跨度,可能也没有⼩到
1px ,但由于其触发频率⾼,滚动跨度⼩,最起码在视觉上就是平滑滚动的了。wheel 只是监听⿏标滚轮事件,但如果是⽤⿏标拖动滚动条,就不会触发此事件,另外的容器元素也就不会跟随滚动了这个其实很好解决,⽤⿏标拖动滚动条肯定是能触发
scroll 事件的,⽽在这种情况下,你肯定能够很轻易地判断出这个被拖动的滚动条是属于哪个容器元素的,只需要处理这个容器的滚动事件,另外⼀个跟随滚动容器的滚动事件不做处理即可。wheel 事件的兼容问题wheel 事件是
DOM Level3 的标准事件,但是除了此事件之外,还有很多⾮标准事件,不同的浏览器内核使⽤不同的标准,所以可能还需要按情况来进⾏兼容,具体可见MDN MouseWheelEvent 实时判断如果你难以忍受
wheel 的弹跳,以及各种兼容,那么其实还有另外的路可以⾛得通,依旧是
scroll 事件,只不过需要做⼀些额外的⼯作。scroll 事件的问题在于,没有判断当前主动滚动的是哪⼀个容器元素,只要确定了主动滚动的容器元素,这事就好办了,例如上述使⽤
wheel 事件中,⽤⿏标拖动滚动条之所以能够使⽤
scroll 事件,就是因为能够很容易地确定当前主动滚动容器元素是哪⼀个。所以,问题的关键在于,如何判断出当前主动滚动的容器元素,只要解决了这个问题,剩下的就很好办了。不论是⿏标滚轮滚动还是⿏标按在滚动条上拖动滚动条滚动,都会触发
scroll 事件,并且这个时候,在坐标系
Z 轴上,⿏标的坐标肯定是位于滚动容器元素所占的⾯积之内的,也就是说,在
Z 轴上,⿏标肯定是悬浮或者位于滚动容器元素之上。⿏标在屏幕上移动的时候,是可以获取到⿏标当前坐标的。其中,
clientX 和
clientY 就是当前⿏标相对于视⼝的坐标,可以认为,只要这个坐标在某个滚动容器的范围内,则认为这个容器元素就是主动滚动容器元素,容器元素的坐标范围可以使⽤
getBoundingClientRect 进⾏获取。下⾯是⿏标移动到
.left 元素中的⽰例代码:if (X> && X< && Y>) { // 进⼊ .left元素中}这样确实是可以的,不过考虑到两个滚动容器元素⼏乎占据了整个屏幕⾯积,所以
mousemove 所要监听的⾯积未免有点⼤,对于性能可能要求较⾼,所以其实可以换成
mouseover 事件,只需要监听⿏标有没有进⼊到某个滚动容器元素即可,也省去上述的坐标判断了。addEventListener('mouseover',function(){ // 进⼊ .left滚动容器元素内})当确定了⿏标主动滚动的容器元素是哪⼀个时,只需要处理这个容器的滚动事件,另外⼀个跟随滚动容器的滚动事件不做处理即可。嗯,效果很不错,性能也很好,
perfect ,可以收⼯喽~按⽐例滚动上述⽰例全部是在两个滚动容器元素的内容⾼度完全⼀致的情况下的效果,如果这两个滚动容器元素的内容⾼度不同呢?那就是下⾯这种效果:可见,由于两个滚动容器元素的内容⾼度不同,所以最⼤的
scrollTop 也就不同,就会出现当其中⼀个
scrollTop 值较⼩的元素滚到底时,另外⼀个元素还停留在⼀半,或者当其中⼀个
scrollTop 值较⼤的元素才滚到⼀半时,另外⼀个元素就已经滚到底了。这种情况很常见,例如你⽤
markdown 写作时,⼀个⼀级标题标记
# 在编辑模式下占⽤的⾼度,⼀般都是⼩于预览模式占⽤的⾼度的,这样就出现了左右两侧滚动⾼度不⼀致的情况。所以,如果将这种情况也考虑进来的话,那么就不能简单地为两个滚动容器元素相互设置
scrollTop 值那么简单。虽然⽆法固定住滚动容器内容的⾼度,但是有⼀点可以确定,滚动条最⼤滚动⾼度,或者说
scrollTop 的值,肯定是与滚动容器内容的⾼度与滚动容器本⾝的⾼度呈⼀定的关系。由于需要知道滚动容器内容的⾼度,还要存在滚动条,所以需要给此容器元素加个⼦元素,⼦元素⾼度不限,就是滚动容器内容的⾼度,容器⾼度固定,溢出滚动即可。
scrollTop ),⽽这两个⾼度值基本上都是可以获取到的,所以就能得到
scrollTop因此,想要让两个滚动元素容器等⽐例上下滚动,即其中⼀个元素滚到头或者滚到底,另外⼀个元素也能对应滚到头和滚到底,那么只要得到这两个滚动容器元素之间的
scrollTop 最⼤值的⽐例(
scale )就⾏了。确定了
scale 之后,实时滚动时,只需要获取主动滚动容器元素的
scrollTop1 ,就能得到另外⼀个跟随滚动的容器元素对应的scrollTop2 :思路弄清晰了,写代码就是很容易的事情了,效果如下:很顺滑~⼩结上述本上已经实现了需求,可能在实践过程中还需要根据实际情况来进⾏⼀定的修改,例如如果你编写⼀个
markdown 的在线编辑和预览页⾯,就需要根据输⼊内容的⾼度实时更新
scale 值,不过主体已经搞定,⼩修⼩改就没什么难度了。另外,本⽂所述不仅是针对两个滚动容器元素的跟随滚动,同时也可扩展开来,更多的元素间的跟随滚动都是可以根据本⽂思路来实现的,本⽂只是为了⽅便讲解⽽具体到了两个元素上。总结以上所述是⼩编给⼤家介绍的原⽣JS控制多个滚动条同步跟随滚动效果,希望对⼤家有所帮助,如果⼤家有任何疑问请给我留⾔,⼩编会及时回复⼤家的。在此也⾮常感谢⼤家对的⽀持!
发布评论