在其他人 post 中找到的滚动平滑代码中发现错误,但不知道如何修复
Bug found in scrolling smooth code found in someone else post but don't know how to fix
我在我的朋友 Google 上搜索了一些实现平滑滚动的代码并找到了这个:
它运行良好,但如果我滚动一次然后尝试使用我的鼠标手动移动滚动条,它就坏了...
SmoothScroll(document, 120, 12);
function SmoothScroll(target, speed, smooth) {
if (target === document)
target = (document.scrollingElement ||
document.documentElement ||
document.body.parentNode ||
document.body) // cross browser support for document scrolling
var moving = false
var pos = target.scrollTop
var frame = target === document.body &&
document.documentElement ?
document.documentElement :
target // safari is the new IE
target.addEventListener('scroll', scrolled, {
passive: false
})
target.addEventListener('mousewheel', scrolled, {
passive: false
})
target.addEventListener('DOMMouseScroll', scrolled, {
passive: false
})
function scrolled(e) {
e.preventDefault(); // disable default scrolling
var delta = normalizeWheelDelta(e)
pos += -delta * speed
pos = Math.max(0, Math.min(pos, target.scrollHeight - frame.clientHeight)) // limit scrolling
if (!moving) update()
}
function normalizeWheelDelta(e) {
if (e.detail) {
if (e.wheelDelta)
return e.wheelDelta / e.detail / 40 * (e.detail > 0 ? 1 : -1) // Opera
else
return -e.detail / 3 // Firefox
} else
return e.wheelDelta / 120 // IE,Safari,Chrome
}
function update() {
moving = true
var delta = (pos - target.scrollTop) / smooth
target.scrollTop += delta
if (Math.abs(delta) > 0.5)
requestFrame(update)
else
moving = false
}
var requestFrame = function () { // requestAnimationFrame cross browser
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (func) {
window.setTimeout(func, 1000 / 50);
}
);
}()
}
所以...我希望它在我已经滚动一次但尝试使用鼠标而不是鼠标滚轮移动滚动条时正常工作。
感谢您的帮助!
看来您可以通过在滚动计算之前将 pos
变量重新调整为 scrollTop
来解决此问题。
此外还有一个错误,您的滚动可能会卡在无限渲染循环中,导致您永远不会停止动画。这是由于 delta
成为 .5 < delta < 1
使得请求框架被永远调用。你实际上不能移动 scrollTop
任何小于 1 的东西所以我调整了另一个渲染循环的条件并四舍五入 delta
function scrolled(e) {
// if currently not animating make sure our pos is up to date with the current scroll postion
if(!moving) {
pos = target.scrollTop;
}
e.preventDefault(); // disable default scrolling
var delta = normalizeWheelDelta(e)
pos += -delta * speed
pos = Math.max(0, Math.min(pos, target.scrollHeight - frame.clientHeight)) // limit scrolling
if (!moving) update()
}
function update() {
moving = true;
// scrollTop is an integer and moving it by anything less than a whole number wont do anything
// to prevent a noop and an infinite loop we need to round it
var delta = absRound((pos - target.scrollTop) / smooth)
target.scrollTop += delta
if (Math.abs(delta) >= 1) {
requestFrame(update)
} else {
moving = false
}
}
function absRound(num) {
if(num < 0) {
return -1*Math.round(-1*num);
} else {
return Math.round(num);
}
}
这样当使用滚轮手动调整滚动位置时,它不会跳到原来的位置,而是自行调整到当前滚动位置。
我在我的朋友 Google 上搜索了一些实现平滑滚动的代码并找到了这个:
它运行良好,但如果我滚动一次然后尝试使用我的鼠标手动移动滚动条,它就坏了...
SmoothScroll(document, 120, 12);
function SmoothScroll(target, speed, smooth) {
if (target === document)
target = (document.scrollingElement ||
document.documentElement ||
document.body.parentNode ||
document.body) // cross browser support for document scrolling
var moving = false
var pos = target.scrollTop
var frame = target === document.body &&
document.documentElement ?
document.documentElement :
target // safari is the new IE
target.addEventListener('scroll', scrolled, {
passive: false
})
target.addEventListener('mousewheel', scrolled, {
passive: false
})
target.addEventListener('DOMMouseScroll', scrolled, {
passive: false
})
function scrolled(e) {
e.preventDefault(); // disable default scrolling
var delta = normalizeWheelDelta(e)
pos += -delta * speed
pos = Math.max(0, Math.min(pos, target.scrollHeight - frame.clientHeight)) // limit scrolling
if (!moving) update()
}
function normalizeWheelDelta(e) {
if (e.detail) {
if (e.wheelDelta)
return e.wheelDelta / e.detail / 40 * (e.detail > 0 ? 1 : -1) // Opera
else
return -e.detail / 3 // Firefox
} else
return e.wheelDelta / 120 // IE,Safari,Chrome
}
function update() {
moving = true
var delta = (pos - target.scrollTop) / smooth
target.scrollTop += delta
if (Math.abs(delta) > 0.5)
requestFrame(update)
else
moving = false
}
var requestFrame = function () { // requestAnimationFrame cross browser
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (func) {
window.setTimeout(func, 1000 / 50);
}
);
}()
}
所以...我希望它在我已经滚动一次但尝试使用鼠标而不是鼠标滚轮移动滚动条时正常工作。
感谢您的帮助!
看来您可以通过在滚动计算之前将 pos
变量重新调整为 scrollTop
来解决此问题。
此外还有一个错误,您的滚动可能会卡在无限渲染循环中,导致您永远不会停止动画。这是由于 delta
成为 .5 < delta < 1
使得请求框架被永远调用。你实际上不能移动 scrollTop
任何小于 1 的东西所以我调整了另一个渲染循环的条件并四舍五入 delta
function scrolled(e) {
// if currently not animating make sure our pos is up to date with the current scroll postion
if(!moving) {
pos = target.scrollTop;
}
e.preventDefault(); // disable default scrolling
var delta = normalizeWheelDelta(e)
pos += -delta * speed
pos = Math.max(0, Math.min(pos, target.scrollHeight - frame.clientHeight)) // limit scrolling
if (!moving) update()
}
function update() {
moving = true;
// scrollTop is an integer and moving it by anything less than a whole number wont do anything
// to prevent a noop and an infinite loop we need to round it
var delta = absRound((pos - target.scrollTop) / smooth)
target.scrollTop += delta
if (Math.abs(delta) >= 1) {
requestFrame(update)
} else {
moving = false
}
}
function absRound(num) {
if(num < 0) {
return -1*Math.round(-1*num);
} else {
return Math.round(num);
}
}
这样当使用滚轮手动调整滚动位置时,它不会跳到原来的位置,而是自行调整到当前滚动位置。