如何控制滚动条到指定位置?
当页面上有四篇文章,如何控制指定文章置顶
<article>
<h1>文章一</h1>
<p>这是文章一的内容</p>
</article>
<article>
<h1>文章二</h1>
<p>这是文章二的内容</p>
</article>
<article>
<h1>文章三</h1>
<p>这是文章三的内容</p>
</article>
<article>
<h1>文章四</h1>
<p>这是文章四的内容</p>
</article>
方法一:锚点
// 获取所有article元素,并为它们添加id属性
const articles = document.querySelectorAll('article');
articles.forEach((item, index) => item.setAttribute('id', 'article-' + (index + 1)));
const scrollToAnchor = (anchor) => {
window.location.hash = anchor;
}
// 滚动到文章三的位置
scrollToAnchor('article-3');
优点:可靠性高
缺点:需要添加不必要的属性,且不能控制距离顶部的偏移量,如果顶部有遮盖层,会被遮盖
方法二:获取元素距离顶部的偏移量,通过js控制滚动条到指定位置
// 获取所有article元素,并计算它们的offsetTop值
const articles = document.querySelectorAll('article');
const offsetTops = []
articles.forEach((item, index) => offsetTops.push(item.offsetTop));
const scrollToArticle = (index, offset = 0) => {
// scrollTo接受两个参数,第一个参数是x轴的偏移量,第二个参数是y轴的偏移量。如果只传递一个参数,那么默认第二个参数为0。
// window.scrollTo(0, offsetTops[index - 1] - offset)
// 想要滚动条的滚动行为更加丝滑可以添加behavior: 'smooth',但是需要浏览器支持
window.scrollTo({ left: 0, top: offsetTops[index - 1] - offset, behavior: 'smooth' })
};
// 滚动到文章二的位置,且距离顶部100px
// scrollToArticle(2);
// 滚动到文章三的位置,且距离顶部100px
scrollToArticle(3, 100);
优点:可以控制元素滑到顶部后的偏移量,且可以添加smooth值让滚动变得丝滑
缺点:需要知道产生滚动条的元素,否则无法生效
当产生滚动条的元素不是windows元素时,window.scrollTo就会失效
<div style="height: 300px;overflow: auto;">
<article>
<h1>文章一</h1>
<p>这是文章一的内容</p>
</article>
<article>
<h1>文章二</h1>
<p>这是文章二的内容</p>
</article>
<article>
<h1>文章三</h1>
<p>这是文章三的内容</p>
</article>
<article>
<h1>文章四</h1>
<p>这是文章四的内容</p>
</article>
</div>
此时我们需要先获取产生滚动条的父元素,将window替换为这个父元素
// 获取所有article元素,并计算它们的offsetTop值
const articles = document.querySelectorAll('article');
// 判断元素是否产生滚动条
function hasScrollbar(element) {
return element.scrollHeight > element.clientHeight;
}
// 获取产生滚动条的元素
function getHasScrollbarEle(element) {
return hasScrollbar(element) ? element : getHasScrollbarEle(element.parentElement);
}
const scrollDom = getHasScrollbarEle(articles[0]);
const offsetTops = []
articles.forEach((item, index) => offsetTops.push(item.offsetTop));
const scrollToArticle = (index, offset = 0) => {
// scrollTo接受两个参数,第一个参数是x轴的偏移量,第二个参数是y轴的偏移量。如果只传递一个参数,那么默认第二个参数为0。
// window.scrollTo(0, offsetTops[index - 1] - offset)
// 想要滚动条的滚动行为更加丝滑可以添加behavior: 'smooth',但是需要浏览器支持
scrollDom.scrollTo({ left: 0, top: offsetTops[index - 1] - offset, behavior: 'smooth' })
};
// 滚动到文章二的位置,且距离顶部100px
// scrollToArticle(2);
// 滚动到文章三的位置,且距离顶部100px
scrollToArticle(3, 100);
缺点:如果页面情况更加复杂,此方案还是会产生不可预料的问题
方案三:scrollIntoView
// 获取所有article元素
const articles = document.querySelectorAll('article');
function scrollToArticle(index) {
articles[index - 1].scrollIntoView({
// 定义垂直方向的对齐 start、center、end 或 nearest
block: 'start',
// 定义水平方向的对齐 start、center、end 或 nearest
inline: 'nearest',
behavior: 'smooth'
});
}
scrollToArticle(2)
优点:代码简单,可靠性高
缺点:不能指定偏移量
改进:
// 在当前元素的前面添加一个兄弟元素
const brotherDom = document.createElement("div");
const styles = {
height: `${offset}px`,
width: "100%",
position: "absolute",
left: "0",
transform: "translateY(-100%)",
background: "transparent",
zIndex: "-1",
};
Object.keys(styles).forEach(key => {
brotherDom.style[key] = styles[key];
});
const parentNode = element.parentNode;
parentNode.style.position = parentNode.style.position || "relative";
parentNode.insertBefore(brotherDom, element);
brotherDom.scrollIntoView({ behavior: "smooth" });
使用:
// 将指定元素置顶且偏移100px
scroll(document.querySelectorAll('article')[2], 100)