滑动-滚动相关

Posted by Youzi on July 22, 2021

JS中滑动、滚动相关的API

相关API有:onscroll, scrollTop, scrollHeight, window.scroll, window.scrollBy, window.scrollTo

onscroll

DOM元素的事件,当元素滚动条滚动时,触发的事件;也可以是window, document.body等对象上绑定;值得注意的是,滚动事件一般是作用在设置了overflow: scroll元素上;

1
2
3
4
5
6
7
let el = `
          <div class="scrollEl" style="height: 100px; overflow: auto;">
            <div style="height: 200px;"></div>
          </div>
          `
let scrollEl = document.querySelector('.scrollEl')
scrollEl.onscroll = (e) => {}

scrollTop

这是DOM元素的属性,指元素滚动条内的顶部隐藏的部分;特指元素内部视窗距离元素顶部的距离;该元素可以被读写

1
2
3
4
5
6
const el = document.querySelector('.el')
const top = el.scrollTop
el.scrollTop = 10

// 取页面当前的滑动距离(距顶部)
const windowScrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0

对应的其他属性还有scrollLeft, window.pageXOffset

scrollHeight

元素滚动条内的内容高度;和scrollTop一样,但是这个属性是只读的;类似的还有scrollWidth

window.scroll(), window.scrollTo(), window.scrollBy()

这三个都是挂载在全局对象上的方法;

  • window.scroll,接受参数x, y坐标值,或{top,left, behavior},将window的滚动条移动到(x,y)坐标,左上角的坐标基准点是(0,0),向右向下递增;
  • window.scrollBy,接受参数x, y,参数指的是滚动的坐标,正数代表向右或向下移动对应的值,负数代表向上或向左;
  • window.scrollTo,和window.scroll一样。

实用方法

实现锚点

  • 传统方式:利用<a href="#id">,不过如果项目也用的前端路由的hash模式实现的页面跳转,这种模式虽然也能实现跳转,但是会改变全局的url,导致一些预料外的bug;

  • 利用scroll相关的api;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<span onclick="goAnchor('#anchor')">锚点</span>
<div  id="anchor">一些内容</div>
<script>
const goAnchor = (id) => {
  const el = document.querySelector(id)
  window.scrollTo({
    top: el.offsetTop,
    behavior: 'smooth'
  })
}
// 另一种方案
const goAnchor2 = (id) => {
  const el = document.querySelector(id)
  el.scrollIntoView({ behavior: 'smooth' })
}
</script>

实际写的时候发现即使用了behavior: 'smooth',也不是平滑的滚动,所以利用requestAnimationFrame做一下平滑处理;

1
2
3
4
5
6
7
8
9
10
11
12
13
const raf = (id, timeout) => {
  let start = performance.now()
  let h = document.querySelector(id).offsetTop
  const time = timeout
  // 这个函数是线性平滑的曲线函数
  const f = (t) => {
    document.documentElement.scrollTop = Math.max(h - (t - start) / time * h, 0)
    if((t - start) < time) {
      window.requestAnimationFrame(f)
    }
  }
  window.requestAnimationFrame(f)
}

也可以利用其他的动画曲线函数,比较常用的贝塞尔曲线公式有easeInOutCubic,渐入渐出的一种函数;