改进小说阅读器技术点

小说阅读器技术改进点

http://www.zhangxinxu.com/wordpress/2018/02/container-scroll-position-hold/

看到这篇文章,与自己之前做的小说阅读器技术点有些相似,特此记录。

一:需求:

注意:外层边框不用看,这是hexo系统对图片设置的边框

但是正常情况下我们对页面进行resize的时候是这样的情况:

当滚动容器尺寸发生变化时,最上面的元素要保持 不变,这样视觉体验比较好。

二:实现

1.原理:

(1).页面scroll时,获取最靠近滚动容器上边缘的元素target

(2).页面scroll时,获得target元素距离滚动容器上边缘的距离值offsetTop。

(3).页面resize时(当滚动容器尺寸改变后),获得target元素之前距离上边缘的offsetTop值与现在target元素距离上边缘的距离值currentOffsetTop的差,进行调整。

2.注意:实现第一步的关键点是有一个api:document.elementsFromPoint方法

之前做小说阅读器的时候,我也需要获取到这个元素,但是当时不知道这个api,所以用的方法是对所有p进行遍历,对left值相同的p分为一组,与当前页面所记录的left值相同的那一组的第一个p标签就是target元素

1
ar elements = document.elementsFromPoint(x, y);

表示返回所有距离浏览器可视窗口x, y坐标的DOM元素集合。因此,elements是一个从最子元素开始,依次向上,一直到<body><html>元素的类数组集合。

在本例中,elements[0]就是我们需要的元素。

3.代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var eleBox = document.getElementById('box');

if (!document.elementsFromPoint) {
document.elementsFromPoint = document.msElementsFromPoint;
}

// 当前最靠近滚动容器上边缘的元素
var targetEle = null;
// 最上边元素和滚动容器上边缘的偏移大小
var topPOffset = false;
/**
* 存储滚动时候最上边缘元素以及偏移大小
*/
var funStorePos = function () {
var bounce = eleBox.getBoundingClientRect();
var pointX = bounce.left + eleBox.clientWidth / 2;
var pointY = bounce.top + 1;

targetEle = document.elementsFromPoint(pointX, pointY)[0];

if (targetEle == eleBox) {
topPOffset = false;
return;
}

topPOffset = Math.round(targetEle.getBoundingClientRect().top - bounce.top);
};

// 滚动时候记录此时最上边缘元素
eleBox.addEventListener('scroll', funStorePos);

// 尺寸变化时候实时修正滚动位置,使最上边缘元素永远在上边缘
window.addEventListener('resize', function () {
if (topPOffset === false) {
return;
}

var scrollTop = eleBox.scrollTop;
// 之前最靠近边缘元素当前的偏移等
var currentTopPOffset = Math.round(targetEle.getBoundingClientRect().top) - Math.round(eleBox.getBoundingClientRect().top);
// 滚动修正
eleBox.scrollTop = scrollTop + (currentTopPOffset - topPOffset);
});