完整代码及动画运行效果:https://codepen.io/TristanBLG...
代码中实现了滚动页面至相应元素的功能,有疑问的地方在于代码利用Math.ceil、Math.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 }); }) }) 