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)

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值