如何在窗口大小调整后保持滚动位置?

问题描述:

我正在构建一个Chrome扩展,它可以让你在网页上保存你的滚动位置。我遇到的问题通常是当您调整页面的大小时,您正在查找的内容可能已被推到位,并且不再位于同一个滚动位置。我一直在尝试构建一些能够调整滚动位置以适应调整大小的内容。我发现this solution,它更接近我所寻找的,但它仍然是一些不准确的。它使用文档的高度和滚动位置来确定您的百分比。然后在您调整页面大小时尝试维持该百分比。不幸的是,百分比并不完全准确。如何在窗口大小调整后保持滚动位置?

我已经将它集成到我的扩展中,并且我一直在尝试在这wikipedia article(我喜欢图纸)。我已在下面添加屏幕截图来展示它的可能性。我试图将高度增量乘以一个常数,但没有单一的数字是有效的。我试图将数字四舍五入到不同的点,但同样的问题。我能做些什么来使滚动位置更准确?

manifest.json的

{ 
    "name": "ScrollMark", 
    "description": "Save your place on a page", 
    "version": "1.1", 
    "manifest_version": 2, 
    "content_scripts": [{ 
     "js": ["jquery.min.js", "contentScript.js"], 
     "matches": ["http://*/*", "https://*/*"] 
    }] 
} 

contentScript.js

$(document).keypress(function (e) { 
    if (e.which == 13) { 
     console.group("User hit enter"); 
     console.log('window size', $(window).width(), $(window).height()); 
     console.log('document size', $(document).width(), $(document).outerHeight(true));   
     console.log('scroll top', $(document).scrollTop()); 
     console.groupEnd(); 
    } 
}); 
(function() { 
    var pageHeight = $(document).outerHeight(true), //get hight of element, including margin 
     scrollPosition = $(document).scrollTop(), 
     scrollPercent = scrollPosition/pageHeight, 
     resizing = false, 
     resizeTimer; 
    $(window).scroll(function() { 
     if (!resizing) { 
      scrollPosition = $(document).scrollTop(); 
      scrollPercent = scrollPosition/pageHeight; 
     } 
    }); 
    $(window).resize(function() { 
     resizing = true; 
     clearTimeout(resizeTimer); 
     resizeTimer = setTimeout(function() { 
      resizing = false 
     }, 500); 
     pageHeight = $(document).outerHeight(true); 
     $(document).scrollTop(scrollPercent * pageHeight); 
    }); 
})(); 

100% View 100%查看 预计滚动的位置:962 实际滚动位置:962 75% View 75%查看 预期滚动位置:1207 实际滚动地点:1211 50% View 50%查看 预计滚动位置:1534 实际滚动地点:1577 25% View 25%查看 预计滚动位置:2852 实际滚动地点:2708

要完全按照你想要的方式,它是不幸的,因为你无法知道响应式设计在调整大小后如何处理内容(当然,你可以,但需要数年的时间来编写这样的代码)。

但是,如果我可能会给你一条建议,那就是依靠最顶端的可见元素。你可以遍历所有的DOM树,并找到最接近屏幕可见部分顶部的静态元素(使用偏移属性等),然后存储它的完整和精确的CSS选择器。

然后,所有你需要做恢复滚动位置:

var el = document.querySelector(storedSelector); 

el && el.scrollIntoView(); 

这会不会是那样精确,你可能想,但它应该没问题。

如果您仍然想要更高的精度,除了选择器之外,还可以存储一些偏移值,并多滚动一些,但这可能非常棘手。

希望这会有所帮助。

+0

我采取这种做法,在一个项目中我的工作,我在那里拿到了第一个:可见对象和使用scrollTo尝试主要滚动条的位置在浏览器中调整大小后。当用户增加浏览器的大小时,大多数情况下它是有效的,但是当缩小时,事情就会变得很糟糕。我不得不添加代码来检测窗口是否缩小,并获取LAST项目而不是第一个项目(如果窗口正在增长,这可以正常工作)。我用这个项目在桌面上敲了很多头 - 希望这可以帮助别人嘻嘻 – Losbear 2016-11-30 16:30:26

我在找同样的事情,但没有找到任何有希望的东西。我是js的初学者,但做了一个工作脚本。它在滚动期间选择屏幕上可见的html元素,并在调整大小期间保持与所选元素相关的滚动位置。我很安静地相信我的代码并不完美,但这是我没有很多经验就可以做到的。希望我能帮助任何人。

var html_tags = []; 
 
\t var public_closest; 
 
\t var from_top_pos; 
 
\t var public_body_height; 
 

 
\t 
 
function start() { 
 
\t \t when_scroll(); 
 
\t \t when_resize(); 
 
\t } 
 

 

 
function when_resize() { 
 
\t 
 
\t \t var count_elements = document.body.childNodes; 
 
\t \t var element = count_elements[public_closest]; 
 
\t \t var closest_pos = count_elements[public_closest].offsetTop; 
 
\t \t var window_height = window.pageYOffset; 
 
\t \t 
 
\t \t window.scrollTo(0, closest_pos + from_top_pos); 
 
\t } 
 

 

 

 

 
function when_scroll() { 
 

 
\t var window_height = document.body.scrollHeight; 
 
\t 
 
\t if (isNaN(public_body_height)) { 
 
\t \t \t public_body_height = window_height; 
 
\t \t } 
 
\t 
 
\t 
 
\t if (public_body_height != window_height) { 
 
\t \t public_body_height = window_height; 
 
\t } else { 
 

 
\t \t var how_many_elems = document.body.childNodes; 
 
\t \t var closest_number; 
 
\t \t var i; 
 
\t \t 
 
\t \t for (i = 0; i < how_many_elems.length; i++) { 
 
\t \t \t \t html_tags[i] = how_many_elems[i].offsetTop; 
 
\t \t \t } 
 
\t \t \t \t 
 
\t \t var closest; 
 
\t \t 
 
\t \t for (i = 0; i < html_tags.length; i++) { \t 
 
\t \t \t if (isNaN(html_tags[i])) { 
 
\t \t \t \t } else { 
 
\t \t \t \t \t 
 
\t \t \t \t \t if (isNaN(closest)) { 
 
\t \t \t \t \t \t \t closest = html_tags[i]; 
 
\t \t \t \t \t \t } 
 
\t \t \t \t \t \t \t 
 
\t \t \t \t \t if (Math.abs(window.pageYOffset - html_tags[i]) <= Math.abs(window.pageYOffset - closest)) { 
 
\t \t \t \t \t \t \t \t closest = html_tags[i]; 
 
\t \t \t \t \t \t \t \t closest_number = i; 
 
\t \t \t \t \t \t \t } \t 
 
\t \t \t \t } 
 
\t \t \t } 
 
\t \t \t 
 
\t \t \t if (isNaN(public_closest)) { 
 
\t \t \t \t } else { 
 
\t \t \t \t \t how_many_elems[public_closest].style.border = "dotted 2px #33aaff"; 
 
\t \t \t \t } 
 
\t \t \t 
 
\t \t public_closest = closest_number; 
 
\t \t how_many_elems[closest_number].style.border = "dotted 4px #FF55AA"; 
 
\t \t \t \t 
 
\t \t var count_elements = document.body.childNodes; 
 
\t \t var element = count_elements[public_closest]; 
 
\t \t var current_height = count_elements[public_closest].offsetTop; 
 
\t \t var window_height = window.pageYOffset; 
 
\t \t var height_difference = window_height - current_height; 
 
\t \t 
 
\t \t from_top_pos = height_difference; 
 

 
\t } 
 
}
body>div { 
 
\t \t float:left; 
 
\t \t width:35%; 
 
\t \t min-width:200px; 
 
\t \t min-height:200px; 
 
\t \t max-height:1000px; 
 
\t \t margin:30px 10px; 
 
\t \t padding:20px 10px; 
 
\t \t font-size:22px; 
 
\t \t color:#33aaff; 
 
\t \t background-color:#ffffff; 
 
\t \t border:dotted 2px #33aaff; 
 
\t \t overflow:hidden; 
 
\t }
<body onload="start()" onscroll="when_scroll()" onresize="when_resize()"> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at  urna. Mauris nec venenatis sapien, et auctor ex. Donec vel urna vulputate, volutpat augue non, bibendum quam. Maecenas congue id justo nec feugiat. Mauris non molestie leo. Duis non tincidunt nibh. Duis tristique dapibus sapien id commodo. In et tempor lorem.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna. Mauris nec venenatis sapien, et auctor ex. Donec vel urna vulputate, volutpat augue non, bibendum quam. Maecenas congue id justo nec feugiat. Mauris non molestie leo.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna. Mauris nec venenatis sapien, et auctor ex. Donec vel urna vulputate, volutpat augue non, bibendum quam.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. ullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna. Mauris nec venenatis sapien, et auctor ex.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est.Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna. Mauris nec venenatis sapien, et auctor ex. Donec vel urna vulputate, volutpat augue non, bibendum quam. Maecenas congue id justo nec feugiat. Mauris non molestie leo. Duis non tincidunt nibh. Duis tristique dapibus sapien id commodo. In et tempor lorem.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna. Mauris nec venenatis sapien, et auctor ex. Donec vel urna vulputate, volutpat augue non, bibendum quam. Maecenas congue id justo nec feugiat. Mauris non molestie leo.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna. Mauris nec venenatis sapien, et auctor ex. Donec vel urna vulputate, volutpat augue non, bibendum quam.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna. Mauris nec venenatis sapien, et auctor ex.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio. Nullam vel massa ut nisl sollicitudin ullamcorper a at urna.</p> 
 
</div> 
 

 
<div> 
 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed urna pellentesque, commodo ante ut, porttitor est. Nullam viverra dignissim sem, ac auctor dui. Phasellus ut neque odio.</p> 
 
</div> 
 

 
</body>

+1

我不知道比这更好的方法,但我会提到在每个滚动事件中运行如此多的代码可能会降低用户的帧速率。使用计时器来限制检测距离屏幕顶部最近的元素的速率是有意义的。 – 2017-09-07 08:37:51