JS 滚动条控制

如何控制滚动条到指定位置?

当页面上有四篇文章,如何控制指定文章置顶

  <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 scroll = (element, offset = 0) => {
// 在当前元素的前面添加一个兄弟元素
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)


posted @ 2024-07-20 13:46  Aguest  阅读(66)  评论(0)    收藏  举报