html中两个textarea同步滚动
两个textarea同步滚动的问题
关于两个textarea之间同步滚动的事件绑定很容易写出来,但是之前发现两个textarea直接简单地相互绑定scroll的话,滚动起来会非常地卡顿,无法正常使用。所以这里主要是解决这个问题。
分析
直接绑定scroll时,当elem1设定了elem2的scrollTop时,触发了elem2的scroll事件,然后设定了elem1的scrollTop,进而重复触发了elem1的scroll事件。 我个人把这种现象叫做事件回响。
之前有尝试过每次scroll事件发生时把另一个元素的scroll事件去掉,scroll后再重新绑定上,但是发现不起作用。 后来猜测是因为移除事件不是即时的,需要一定的时间,所以在设定scroll值时另一个元素的scroll事件还在,回响现象依然发生。
后来采用的是以下方法:在元素1滚动时,把元素2的滚动事件解除,且在100毫秒的倒计时后重新绑定上。 个人觉得这种方式性能很好, 因为滚动事件大多数情况下是连续触发,解除元素2的事件后可以完全消除回响现象, 提高性能。 且在100毫秒的时间内,一般人做不到马上切换到另一个元素。
实际同步滚动效果很斯滑, 和单独滚动一个textarea没什么区别。
代码
主要的js代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta title="Scroll Test"/>
<style type="text/css" rel="stylesheet">
*{margin:0; padding: 0}
body{display: flex; padding: 10px;justify-content: space-around;}
#text1,#text2{width: calc(50% - 10px); height: calc(100vh - 20px); resize: none;padding: 2px; box-sizing: border-box;}
</style>
</head>
<body>
<textarea id="text1"></textarea>
<textarea id="text2"></textarea>
<script type="text/javascript">
window.onload = function(){
let text1 = document.getElementById('text1');
let text2 = document.getElementById('text2');
// 绑定同步滚动
bindScroll(text1, text2);
}
/**
* 绑定同步滚动
* elem1 滚动元素1
* elem2 滚动元素2
*/
function bindScroll(elem1, elem2){
let timeout1;
let timeout2;
let elem1Func = function(e){
// 如果elem2上已有滚动事件,先解绑
!timeout1 && elem2.removeEventListener('scroll', elem2Func);
elem2.scrollTo(e.target.scrollLeft, e.target.scrollTop);
// 清空倒计时
timeout1 && clearTimeout(timeout1);
// 滚动后,100毫秒倒计时后重新绑定滚动事件
timeout1 = setTimeout(function(){elem2.addEventListener('scroll', elem2Func); timeout1 = undefined;}, 100);
};
let elem2Func = function(e){
!timeout2 && elem1.removeEventListener('scroll', elem1Func);
elem1.scrollTo(e.target.scrollLeft, e.target.scrollTop);
timeout2 && clearTimeout(timeout2);
timeout2 = setTimeout(function(){elem1.addEventListener('scroll', elem1Func); timeout2 = undefined;}, 100);
};
elem1.addEventListener('scroll', elem1Func);
elem2.addEventListener('scroll', elem2Func);
}
</script>
</body>
</html>