基于#B5C7E5→#C8BFE7渐变色系的动态加载进度条
// ==UserScript==
// @name Via加载进度条
// @namespace https://viayoo.com/
// @version 2.4.0
// @description 基于#B5C7E5→#C8BFE7渐变色系的动态加载进度条
// @author 是小白呀 & DeepSeek & Grok
// @match *://*/*
// @license MIT
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const LOADER_THEME = {
PRIMARY: '#B5C7E5',
SECONDARY: '#C8BFE7',
GLOW: '#D4B1FF',
DURATION: 380,
HEIGHT: 2.5,
HIDE_DELAY: 200
};
// 创建带有Shadow DOM的加载器
const createLoader = () => {
// 移除现有的加载器(如果有)
const existingHost = document.getElementById('via-loader-host');
if (existingHost) existingHost.remove();
// 创建Shadow Host
const shadowHost = document.createElement('div');
shadowHost.id = 'via-loader-host';
Object.assign(shadowHost.style, {
position: 'fixed',
top: '0',
left: '0',
width: '100%',
height: '0',
zIndex: '99999',
pointerEvents: 'none'
});
// 创建Shadow Root
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
// 创建样式
const style = document.createElement('style');
style.textContent = `
.via-loader {
width: 0%;
height: ${LOADER_THEME.HEIGHT}px;
background: linear-gradient(135deg,
${LOADER_THEME.PRIMARY} 25%,
${LOADER_THEME.SECONDARY} 50%,
${LOADER_THEME.GLOW} 75%,
${LOADER_THEME.PRIMARY} 100%);
background-size: 200% 100%;
transition: width ${LOADER_THEME.DURATION}ms ease-out,
opacity ${LOADER_THEME.DURATION / 2}ms ease-in;
box-shadow: 0 2px 6px ${LOADER_THEME.SECONDARY}33;
}
`;
// 创建加载器元素
const loader = document.createElement('div');
loader.className = 'via-loader';
// 添加到Shadow DOM
shadowRoot.appendChild(style);
shadowRoot.appendChild(loader);
// 添加到文档
document.documentElement.appendChild(shadowHost);
return {
host: shadowHost,
element: loader
};
};
class LoadingSystem {
constructor() {
this.loader = createLoader();
this.pageLoadStatus = false;
this.initLoader();
}
initLoader() {
this.setupLoadingSimulator();
this.setupSPAListener();
}
setupLoadingSimulator() {
let progress = 0;
const baseSpeed = 0.05;
const networkFactor = navigator.connection
? Math.min(navigator.connection.downlink / 5, 1)
: 1;
const animate = () => {
if (this.pageLoadStatus) return;
const dynamicSpeed = baseSpeed *
Math.pow(1 - progress / 100, 0.7) *
(0.8 + Math.random() * 0.4) *
networkFactor;
progress = Math.min(progress + dynamicSpeed * 100, 99.9);
this.loader.element.style.width = `${progress}%`;
this.loader.element.style.backgroundPositionX =
`${Math.sin(Date.now()/800)*50 + 50}%`;
requestAnimationFrame(animate);
};
animate();
const completeHandler = () => {
this.pageLoadStatus = true;
this.loader.element.style.width = '100%';
setTimeout(() => {
this.loader.element.style.opacity = '0';
setTimeout(() => {
if (this.loader.host.parentNode) {
this.loader.host.parentNode.removeChild(this.loader.host);
}
}, LOADER_THEME.DURATION);
}, LOADER_THEME.HIDE_DELAY);
};
window.addEventListener('load', completeHandler, { once: true });
document.addEventListener('DOMContentLoaded', () => {
if (!this.pageLoadStatus) setTimeout(completeHandler, 1500);
});
}
setupSPAListener() {
const resetLoader = () => {
if (this.pageLoadStatus) {
this.pageLoadStatus = false;
this.loader = createLoader();
this.setupLoadingSimulator();
}
};
const wrapHistory = (method) => {
const orig = history[method];
return function() {
const result = orig.apply(this, arguments);
resetLoader();
return result;
};
};
history.pushState = wrapHistory('pushState');
history.replaceState = wrapHistory('replaceState');
window.addEventListener('popstate', resetLoader);
}
}
// 初始化
const init = () => {
if (document.getElementById('via-loader-host')) return;
new LoadingSystem();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
setTimeout(init, 0);
}
})();