全站通知:
Widget:AnchorFix
刷
历
编
跳到导航
跳到搜索
AnchorFix - 修复锚点跳动
措施是替换 jquery 的 animate函数,带有 scrollTop 属性的 animate 不执行
已知副作用:
- #gotop 点击事件,已经用原生js增加了点击回顶部事件。
尚不清楚其他副作用!
源码:
<script>
/**
* 避免锚点乱跑,措施是当jquery的 animate 函数带有 scrollTop 参数时, animate 不执行
*
* 目前 jquery 和 乱搞锚点的 JS ,是在一个文件中加载的:
* load.php?lang=zh-cn&modules=jquery%2Coojs-ui-core%2Coojs-ui-widgets%7Cmediawiki.extra.bili&skin=vector&version=kyo1q
* 因此需要在 jquery 生效后,调用 scrollTop 之前,替换 animate,窗口时间很短
*
* 没有优雅的办法,由于jq加载需要时间,而且Bugfix会提前加载另一份jq,
*
* 目前有效的方案是jq加载后,多次覆盖。
*
* 已知副作用: #gotop 点击事件失效,方案是用原生js实现点击事件。
*
*/
(function() {
var MAX_WAIT_COUNT = 152; // 最长等待 152 x 32ms = 4864ms
// 等待jQuery加载,很激进,每32ms检查一次,然后限制animate函数
function waitJQueryLoad(waitCount) {
if (window.jQuery || waitCount > MAX_WAIT_COUNT) {
jqueryAnimate_YouthPlus();
} else{
setTimeout(function() {waitJQueryLoad(waitCount + 1)}, 32); // 每隔32毫秒检查一次jq加载没
}
}
// 开始等待JQ
waitJQueryLoad(0);
function jqueryAnimate_YouthPlus() { // 通过禁用 animate(with scrollTop), 实现“青春版”Animate
var local_animate = null;
console.info('jQuery loaded,准备禁用 animate(with scrollTop)');
let count = 0;
const intervalId = setInterval(() => {
if (count >= 50) {
clearInterval(intervalId);
return;
}
count++;
// 无论如何都尝试覆盖 animate
if(window.jQuery.fn.animate){
if (local_animate === null) {
// 存一个本地的 animate 函数,用于过滤 scrollTop 属性,带有 scrollTop 属性的 animate 不执行
local_animate = window.jQuery.fn.animate;
console.log('禁止 JQuery 的 animate 函数使用 scrollTop 参数,避免锚点跳动。');
}
window.jQuery.fn.animate = function(prop, speed, easing, callback) {
if (prop.scrollTop !== undefined) {
console.warn('已禁止 JQuery 的 animate 函数使用 scrollTop 参数,这是由于相关平台JS会导致锚点跳动。 此次调用的prop参数:', prop);
return this;
}
return local_animate(prop, speed, easing, callback);
};
}
// 目前测试可以不禁用 scrollTop 函数
// window.jQuery.fn.scrollTop = function(val) {
// console.warn('scrollTop function is disabled');
// return this;
// };
}, 10);
}
})();
// 用原生js实现#gotop的点击回顶部事件
document.addEventListener('click', function(event) {
if (event.target.matches('#gotop')) {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}
});
</script>