背景
公司有一个页面,分为三个部分,如下图:
分为三个部分:
第一部分:最左边,分为多个步骤,每一个步骤对应中间部分,和右边内容的滚动高度
第二部分:中间,会根据左边选中的步骤进行切换,同时也会跟进右侧滚动到顶部的模块来进行修改
第三部分:最右边,内容展示,可以进行滚动,与中间和左侧进行联动
整体来说就是,做不切换步骤,中间会变成对应步骤可编辑的内容,右侧会将对应步骤编辑好的内容滚动到页面顶部,反之,如果右侧滚动,也会引起中间内容变化和左侧选中的变化
问题
最近测试那边突然发现,点击左侧导航,右侧出现定位不准确的问题
问题分析
- 我的电脑、测试某些人电脑,无法复现问题,定位是兼容性问题
- 在复现电脑上观察,点击左侧按钮,右侧会正好定位到对应模块的上方一点点,也就差不多1px,只有右侧稍微往上面移动一点点,则左侧就变成正常选中,所以可以断定,根据左侧步骤索引找到的需要滚动的高度,和右侧计算出来滚动的高度不一致
- 左侧选中,是根据右侧当前变红的模块索引,单纯滚动右侧,左侧定位很准确
- 右侧变红,是根据左侧选中项的索引,从而计算右侧应该选中模块的滚动高度scrollTop和当前已经位移的距离offsetTop,从而计算出应该移动的距离,这一步出现问题
尝试
根据左侧索引来计算offsetTop和scrollTop,所以怀疑是否是右侧模块计算offsetTop有兼容性,或者是容器高度计算有兼容性,而且计算滚动距离实际上计算了了两遍,因为渲染页面的时候已经计算出右侧每一个容器都有滚动范围,如下:
_calculateHeight () {
// 清空高度数组
this.listHeight = []
let height = 0
this.listHeight.push(height)
let divObjs = document.getElementsByClassName('content-box')
for (let i = 0; i < divObjs.length; i++) {
let item = divObjs[i]
if (i == 0 || i == 1 || i == 2 || i == 3) {
height += item.clientHeight
} else {
height += parseInt(item.clientHeight + 10)
}
this.listHeight.push(height)
}
}
所以我们不需要根据offsetTop来继续滚动距离,我们只需要取这个数组中对应索引的值即可,这个值就是模块距离父容器的高度
问题还是存在??
满怀信心部署完毕后,发现有问题的电脑,还是有问题
继续找问题
通过打印发现,原来有问题的电脑,打印出来的scrollTop值是浮点型数据类型,这就导致了滚动计算有差异,我们计算滚动距离代码如下:
let jump = document.getElementById(paraIndex)
let scrollBox = document.getElementsByClassName('right-body')[0]
let distance = scrollBox.scrollTop || document.body.scrollTop
// let total = jump.offsetTop - swiperClass
// 减去padding值
let total = this.listHeight[paraIndex];
let step = total / 50
if (total > distance) {
smoothDown()
} else {
// 这个地方如果是用浮点型计算,就是会有计算差异的
let newTotal = distance - total
step = newTotal / 50
smoothUp()
}
function smoothDown () {
if (distance < total) {
// 这个地方如果是用浮点型计算,就是会有计算差异的
distance += step
scrollBox.scrollTop = distance
setTimeout(smoothDown, 10)
} else {
scrollBox.scrollTop = total
}
}
function smoothUp () {
if (distance > total) {
// 这个地方如果是用浮点型计算,就是会有计算差异的
distance -= step
scrollBox.scrollTop = distance
setTimeout(smoothUp, 10)
} else {
scrollBox.scrollTop = total
}
}
由上代码可以看出,浮点型计算加减乘除会出现计算不准确的情况
解决
将滚动scrollToop值向上取整,去掉浮点型数据的情况
let distances = scrollBox.scrollTop || document.body.scrollTop
let distance = !isNaN(distances) ? Math.ceil(distances) : distances;
注意
大部分浏览器的scrollTop值都是整数,现在已经慢慢出现小数了,所以以后要继续加减乘除计算的时候,可以考虑一下小数的情况