提问人:user3840170 提问时间:11/4/2023 最后编辑:user3840170 更新时间:11/24/2023 访问量:439
如何滚动查看 DOM 范围?
How do I scrollIntoView a DOM Range?
问:
Element
接口提供了一个 scrollIntoView
方法,该方法设置所有祖先元素的滚动位置,以便给定元素在屏幕上可见。
如何使用 DOM 范围执行类似的操作,也就是说,滚动需要滚动的任何内容,以便该范围
在屏幕上可见?
我可能可以忍受手动计算范围的边界框并找到要滚动的元素,但我不想以任何方式修改 DOM 的内容。
答:
12赞
Salman A
11/16/2023
#1
Range
有一个有用的方法,称为 getBoundingClientRect
,它返回一个 DOMRect
,用于描述区域相对于视口的位置。然后,可以使用 将元素滚动到视图中。一个非常简单的例子:window.scrollBy
document.querySelector("#scroll-demo").addEventListener("click", function() {
let selection = window.getSelection();
if (selection.rangeCount === 0) {
return;
}
let range = selection.getRangeAt(0);
let rect = range.getBoundingClientRect();
// scroll to top if:
// - some part of selection is above the viewport
// - some part of selection is below the viewport
if (rect.top < 0 || rect.bottom > document.documentElement.clientHeight) {
window.scrollBy(0, rect.y);
}
});
p {
max-width: 30em;
}
p:nth-child(even) {
background-color: #EEE;
}
#demos {
position: fixed;
right: 0;
top: 0;
padding: 1em;
color: #FFF;
background-color: #000A;
}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc aliquam ultricies quam, non porttitor diam iaculis vitae. Nulla rutrum erat et tortor aliquet bibendum. Ut suscipit sapien id accumsan rutrum. Quisque eleifend tempor dolor sit amet luctus.
Quisque non malesuada tortor. Nam sapien orci, consectetur dignissim magna eget, cursus gravida ligula. Quisque efficitur ornare felis, et venenatis ipsum laoreet vel. Sed nunc risus, imperdiet a porttitor eget, auctor eget neque. Donec tincidunt a
est nec sodales. Suspendisse pellentesque est at luctus interdum. Quisque justo orci, vestibulum eget sapien et, faucibus imperdiet turpis. Etiam vel volutpat orci. Nullam tellus elit, bibendum a nulla quis, porttitor euismod sem.</p>
<p>Fusce vehicula nulla quis iaculis commodo. In in efficitur urna. Quisque sem nisl, luctus id porta ac, pellentesque a tellus. Pellentesque lacinia nisl non neque bibendum accumsan. Praesent vitae facilisis dolor. Sed vel ipsum non mauris consequat aliquet.
Pellentesque tellus purus, consequat ut erat convallis, pretium molestie justo.</p>
<p>Maecenas sit amet laoreet leo, vel consectetur purus. Nunc in rhoncus ex. Etiam ultricies mauris ac felis aliquam semper. Morbi eleifend, justo a tincidunt pellentesque, est erat tincidunt nisi, tincidunt dictum nisi ipsum id nunc. Aliquam vel libero
ipsum. In hac habitasse platea dictumst. Curabitur rhoncus risus in ultricies tempus. Vivamus elementum augue ac elit facilisis interdum. Duis tincidunt eget tortor posuere facilisis. Suspendisse fringilla, purus et faucibus tempus, dui elit viverra
arcu, et iaculis massa justo eget ante. Nunc maximus gravida nulla ac tristique. Etiam vel tellus erat.</p>
<p>Nunc vitae risus dignissim, ultricies turpis at, bibendum erat. Mauris at ullamcorper lorem, eget posuere arcu. Aliquam quis libero turpis. Nullam maximus nisl enim, quis pellentesque lacus efficitur non. Fusce consectetur, erat vel elementum porttitor,
risus libero vulputate risus, at porta ante lorem nec lorem. Sed vitae dolor in nisl tincidunt dapibus. Aliquam id velit sit amet ipsum pulvinar condimentum ut quis massa. Aenean id urna a nunc efficitur pulvinar. Ut sed hendrerit lectus. Sed fringilla
urna eu nibh egestas, ac euismod sem hendrerit. Aliquam et risus accumsan, congue leo sed, ornare lacus. Nunc luctus erat odio, ut ultricies dui efficitur ut.</p>
<p>Praesent dapibus est nulla. Cras posuere, risus vel molestie porttitor, ipsum sapien pretium dolor, vitae bibendum arcu massa eget velit. Nunc laoreet lacinia ligula, vel ullamcorper est suscipit finibus. Sed sagittis ipsum vitae odio faucibus porta.
In hac habitasse platea dictumst. Cras vitae consectetur nisl. Ut id arcu condimentum, auctor erat quis, volutpat ligula. Nulla vitae diam at odio dapibus auctor id sed lectus. Integer ac pharetra nisi, ac tincidunt dolor. Cras nec massa et purus dictum
faucibus eget sed nisi. Phasellus interdum urna nec sem lobortis, non condimentum erat porta. Pellentesque sodales sit amet erat ut vulputate. Sed laoreet quis eros quis mollis. Pellentesque scelerisque mauris ornare interdum commodo. Nunc id rhoncus
purus. Nullam sed enim nec ex dignissim pretium.</p>
<div id="demos">
Select something in the document<br>
then scroll it outside the viewport<br>
<button id="scroll-demo">Scroll selection into view</button>
</div>
如果范围存在于嵌套的可滚动容器中,则情况会变得复杂。一个棘手的解决方案是将“最近的滚动父级”滚动到视图中,并将其与视口的顶部对齐,然后使用上述逻辑将范围滚动到视图中(边界矩形将为您提供相对于视口的位置,但此时所有滚动父项都与视口的顶部对齐,因此它应该可以正常工作)。
对于简单的用例,一个简单的解决方案是使用 Range.commonAncestorContainer
并使用 Element.scrollIntoView
标识包含范围的元素:
document.querySelector("#scroll-demo").addEventListener("click", function() {
let selection = window.getSelection();
if (selection.rangeCount === 0) {
return;
}
let range = selection.getRangeAt(0);
let element = range.commonAncestorContainer;
if (element.nodeType === Node.TEXT_NODE) {
element = element.parentElement;
}
element.scrollIntoView();
});
p {
max-width: 30em;
}
p:nth-child(even) {
background-color: #EEE;
}
#scrollable {
max-width: 30em;
height: 20em;
overflow: auto;
box-shadow: 0 0 4px 2px #F00;
}
#demos {
position: fixed;
right: 0;
top: 0;
padding: 1em;
color: #FFF;
background-color: #000A;
}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc aliquam ultricies quam, non porttitor diam iaculis vitae. Nulla rutrum erat et tortor aliquet bibendum. Ut suscipit sapien id accumsan rutrum. Quisque eleifend tempor dolor sit amet luctus.
Quisque non malesuada tortor. Nam sapien orci, consectetur dignissim magna eget, cursus gravida ligula. Quisque efficitur ornare felis, et venenatis ipsum laoreet vel. Sed nunc risus, imperdiet a porttitor eget, auctor eget neque. Donec tincidunt a
est nec sodales. Suspendisse pellentesque est at luctus interdum. Quisque justo orci, vestibulum eget sapien et, faucibus imperdiet turpis. Etiam vel volutpat orci. Nullam tellus elit, bibendum a nulla quis, porttitor euismod sem.</p>
<p>Fusce vehicula nulla quis iaculis commodo. In in efficitur urna. Quisque sem nisl, luctus id porta ac, pellentesque a tellus. Pellentesque lacinia nisl non neque bibendum accumsan. Praesent vitae facilisis dolor. Sed vel ipsum non mauris consequat aliquet.
Pellentesque tellus purus, consequat ut erat convallis, pretium molestie justo.</p>
<p>Maecenas sit amet laoreet leo, vel consectetur purus. Nunc in rhoncus ex. Etiam ultricies mauris ac felis aliquam semper. Morbi eleifend, justo a tincidunt pellentesque, est erat tincidunt nisi, tincidunt dictum nisi ipsum id nunc. Aliquam vel libero
ipsum. In hac habitasse platea dictumst. Curabitur rhoncus risus in ultricies tempus. Vivamus elementum augue ac elit facilisis interdum. Duis tincidunt eget tortor posuere facilisis. Suspendisse fringilla, purus et faucibus tempus, dui elit viverra
arcu, et iaculis massa justo eget ante. Nunc maximus gravida nulla ac tristique. Etiam vel tellus erat.</p>
<div id="scrollable">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc aliquam ultricies quam, non porttitor diam iaculis vitae. Nulla rutrum erat et tortor aliquet bibendum. Ut suscipit sapien id accumsan rutrum. Quisque eleifend tempor dolor sit amet luctus.
Quisque non malesuada tortor. Nam sapien orci, consectetur dignissim magna eget, cursus gravida ligula. Quisque efficitur ornare felis, et venenatis ipsum laoreet vel. Sed nunc risus, imperdiet a porttitor eget, auctor eget neque. Donec tincidunt
a est nec sodales. Suspendisse pellentesque est at luctus interdum. Quisque justo orci, vestibulum eget sapien et, faucibus imperdiet turpis. Etiam vel volutpat orci. Nullam tellus elit, bibendum a nulla quis, porttitor euismod sem.</p>
<p>Fusce vehicula nulla quis iaculis commodo. In in efficitur urna. Quisque sem nisl, luctus id porta ac, pellentesque a tellus. Pellentesque lacinia nisl non neque bibendum accumsan. Praesent vitae facilisis dolor. Sed vel ipsum non mauris consequat aliquet.
Pellentesque tellus purus, consequat ut erat convallis, pretium molestie justo.</p>
<p>Maecenas sit amet laoreet leo, vel consectetur purus. Nunc in rhoncus ex. Etiam ultricies mauris ac felis aliquam semper. Morbi eleifend, justo a tincidunt pellentesque, est erat tincidunt nisi, tincidunt dictum nisi ipsum id nunc. Aliquam vel libero
ipsum. In hac habitasse platea dictumst. Curabitur rhoncus risus in ultricies tempus. Vivamus elementum augue ac elit facilisis interdum. Duis tincidunt eget tortor posuere facilisis. Suspendisse fringilla, purus et faucibus tempus, dui elit viverra
arcu, et iaculis massa justo eget ante. Nunc maximus gravida nulla ac tristique. Etiam vel tellus erat.</p>
<p>Nunc vitae risus dignissim, ultricies turpis at, bibendum erat. Mauris at ullamcorper lorem, eget posuere arcu. Aliquam quis libero turpis. Nullam maximus nisl enim, quis pellentesque lacus efficitur non. Fusce consectetur, erat vel elementum porttitor,
risus libero vulputate risus, at porta ante lorem nec lorem. Sed vitae dolor in nisl tincidunt dapibus. Aliquam id velit sit amet ipsum pulvinar condimentum ut quis massa. Aenean id urna a nunc efficitur pulvinar. Ut sed hendrerit lectus. Sed fringilla
urna eu nibh egestas, ac euismod sem hendrerit. Aliquam et risus accumsan, congue leo sed, ornare lacus. Nunc luctus erat odio, ut ultricies dui efficitur ut.</p>
<p>Praesent dapibus est nulla. Cras posuere, risus vel molestie porttitor, ipsum sapien pretium dolor, vitae bibendum arcu massa eget velit. Nunc laoreet lacinia ligula, vel ullamcorper est suscipit finibus. Sed sagittis ipsum vitae odio faucibus porta.
In hac habitasse platea dictumst. Cras vitae consectetur nisl. Ut id arcu condimentum, auctor erat quis, volutpat ligula. Nulla vitae diam at odio dapibus auctor id sed lectus. Integer ac pharetra nisi, ac tincidunt dolor. Cras nec massa et purus
dictum faucibus eget sed nisi. Phasellus interdum urna nec sem lobortis, non condimentum erat porta. Pellentesque sodales sit amet erat ut vulputate. Sed laoreet quis eros quis mollis. Pellentesque scelerisque mauris ornare interdum commodo. Nunc
id rhoncus purus. Nullam sed enim nec ex dignissim pretium.</p>
</div>
<p>Nunc vitae risus dignissim, ultricies turpis at, bibendum erat. Mauris at ullamcorper lorem, eget posuere arcu. Aliquam quis libero turpis. Nullam maximus nisl enim, quis pellentesque lacus efficitur non. Fusce consectetur, erat vel elementum porttitor,
risus libero vulputate risus, at porta ante lorem nec lorem. Sed vitae dolor in nisl tincidunt dapibus. Aliquam id velit sit amet ipsum pulvinar condimentum ut quis massa. Aenean id urna a nunc efficitur pulvinar. Ut sed hendrerit lectus. Sed fringilla
urna eu nibh egestas, ac euismod sem hendrerit. Aliquam et risus accumsan, congue leo sed, ornare lacus. Nunc luctus erat odio, ut ultricies dui efficitur ut.</p>
<p>Praesent dapibus est nulla. Cras posuere, risus vel molestie porttitor, ipsum sapien pretium dolor, vitae bibendum arcu massa eget velit. Nunc laoreet lacinia ligula, vel ullamcorper est suscipit finibus. Sed sagittis ipsum vitae odio faucibus porta.
In hac habitasse platea dictumst. Cras vitae consectetur nisl. Ut id arcu condimentum, auctor erat quis, volutpat ligula. Nulla vitae diam at odio dapibus auctor id sed lectus. Integer ac pharetra nisi, ac tincidunt dolor. Cras nec massa et purus dictum
faucibus eget sed nisi. Phasellus interdum urna nec sem lobortis, non condimentum erat porta. Pellentesque sodales sit amet erat ut vulputate. Sed laoreet quis eros quis mollis. Pellentesque scelerisque mauris ornare interdum commodo. Nunc id rhoncus
purus. Nullam sed enim nec ex dignissim pretium.</p>
<div id="demos">
Select something in the document<br>
then scroll it outside the viewport<br>
<button id="scroll-demo">Scroll selection into view</button>
</div>
评论
1赞
user3840170
11/17/2023
如果范围位于不是顶级窗口的可滚动元素中,这是否也有效?
0赞
Salman A
11/19/2023
很遗憾,不可以。我能想到的一个快速解决方案是用于定位完全包含范围的元素。如果得到一个元素:继续,如果你得到一个文本节点:find parentElement。然后打电话,希望浏览器完成剩下的工作。Range.commonAncestorContainer
thatElement.scrollIntoView()
3赞
the Hutt
11/20/2023
#2
将范围中的第一个元素带到视口的顶部边框也可以解决该问题:
range.startContainer.scrollIntoView(true);
评论
0赞
user3840170
11/22/2023
当然,请确保至少有一部分范围是可见的;这与对元素(也可以大于视口)执行相同的操作没有太大区别。
评论