完整代码及动画运行效果: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
});
})
})
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.