利用Math.ceil等近似方法是否会影响该滚动动画的精确性?

完整代码及动画运行效果:https://codepen.io/TristanBLG...

代码中实现了滚动页面至相应元素的功能,有疑问的地方在于代码利用Math.ceilMath.round做了一些近似的处理,这是否会影响到页面滚动到对应元素的精确性?涉及到小数总是难以判断.
比如使用Math.ceil处理后会比原始值大0.x,如果要求动画精确一点,这0.x是这个例子中不需要考虑的吗?
为什么有些地方用Math.ceil?而有些地方又用了Math.round?

做了近似处理的地方:
下面的这两处代码作了近似处理,可以知道大致知道它们加起来近似了多少吗? 0.几? 会不会近似处理后离精准位置多了好几pixel,而不仅仅是0.几?

window.scroll(0, Math.ceil((time * (destinationOffsetToScroll - start)) + start))
if(time >= 1 || Math.round(window.pageYOffset) === destinationOffsetToScroll) {}

完整JavaScript代码:

const scrollTo = function({target, duration = 200, callback} = {}){
  if(!target){
    console.error('scrollTo() => You must specify a target.')
    return false
  }
  const targetHref                  = target.getAttribute('href').replace( /^#/ , '')
  const destination                 = document.getElementById(targetHref)
  const start                       = window.pageYOffset
  const startTime                   = 'now' in window.performance ? performance.now() : new Date().getTime()
  const documentHeight              = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight)
  const windowHeight                = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight
  const destinationOffset           = typeof destination === 'number' ? destination : destination.offsetTop
  const destinationOffsetToScroll   = Math.round(documentHeight - destinationOffset < windowHeight ? documentHeight - windowHeight : destinationOffset)

  if('requestAnimationFrame' in window === false) {
      window.scroll(0, destinationOffsetToScroll)
      if(callback) {
          callback()
      }
      return
  }
  
  const scroll = function() {
    const now   = 'now' in window.performance ? performance.now() : new Date().getTime()
    const time  = Math.min(1, ((now - startTime) / duration))
    
    window.scroll(0, Math.ceil((time * (destinationOffsetToScroll - start)) + start))
    
    if(time >= 1 || Math.round(window.pageYOffset) === destinationOffsetToScroll) {
      if(callback) {
        callback()
      }
      return
    }

    requestAnimationFrame(scroll)
  }

  requestAnimationFrame(scroll)
};

const navLink = Array.from(document.querySelectorAll('[href^="#"]'))
  navLink.forEach(el => {
    el.addEventListener('click', function(ev) {
      ev.preventDefault()
      ev.stopPropagation()
      scrollTo({
        duration: 300,
        target: ev.target
      });
    })
})
阅读 1.7k
1 个回答
const time  = Math.min(1, ((now - startTime) / duration))

这个min就能保证消除最后的偏差。now-startTime>duration的时候,也就是超过播放时间了,就直接用1,那么Math.ceil((time * (destinationOffsetToScroll - start)) + start)无论如何都等于destinationOffsetToScroll,就不存在偏差了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题