不固定高度的多节点同步滚动
最近有这么一个功能,用户编辑的时候实现编辑区和预览区同步滚动,但是两边内容的高度是不一样的。
算出比例同步滚动
大体思路是计算每次滚动的距离与该节点整体高度的比例,另一个节点滚动的距离为该比例 * 当前节点的高度。
function syncScroller () {
let nodes = Array.prototype.filter.call(arguments, item => item instanceof HTMLElement)
let max = nodes.length
if (!max || max === 1) return
let sign = 0;
function event () {
if (!sign) {
sign = max - 1;
let top = this.scrollTop
const rate = top / this.scrollHeight
let left = this.scrollLeft
for (node of nodes) {
if (node == this) continue;
node.scrollTo(left, node.scrollHeight * rate);
}
} else
-- sign;
}
nodes.forEach((ele, index) => {
ele.addEventListener('scroll', event);
});
return () => {
nodes.forEach((ele, index) => {
ele.removeEventListener('scroll', event);
});
}
}
但效果却不尽人意,因为有可能编辑区块高度很小,预览区块却很大(如占满整屏),就会造成不同步的现象。
使用 scrollview 实现滚动
只能转变思路了,看到有个 scrollIntoView 的方法,可以将元素滚动至可视区某个位置。那就可以监听滚动区域是第几个元素,将另一边相同顺序的元素滚动至可视区即可。
获取当前滚动元素的 index
const container = this.querySelector('#scrollBlocks')
let currentIndex = 0
if (container?.children) {
[...container?.children].forEach((sectionRef, index) => {
const { offsetTop, clientHeight } = sectionRef
if (this.scrollTop >= offsetTop - clientHeight * (1 / 2)) {
currentIndex = index
}
})
}
以上 function 来自 chatgpt
预览区元素滚动
node.children?.[currentIndex === 0 ? 0 : currentIndex + 1]?.scrollIntoView()
效果图:
这个方法的问题在于不是实时滚动,只会在编辑区滚动到某个元素时,预览区滚动一次,不过也满足当前的需求了。
参考: