mirror of
https://github.com/afoim/fuwari.git
synced 2026-01-31 00:53:19 +08:00
refactor: (性能优化)使友链页面在桌面端Chromium系浏览器不再卡成史
移除所有图片加载时的进度条动画效果,简化DOM结构和CSS样式 默认使用深色主题,优化主题加载逻辑 清理未使用的代码和注释
This commit is contained in:
@@ -47,40 +47,17 @@ const imageClass = "w-full h-full object-cover";
|
||||
const imageStyle = `object-position: ${position}`;
|
||||
---
|
||||
<div id={id} class:list={[className, 'overflow-hidden relative image-wrapper']} style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||
<!-- 加载条 -->
|
||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<!-- 图片内容 -->
|
||||
{isLocal && img && <Image src={img} alt={alt || ""} class={`${imageClass} image-content opacity-0 transition-opacity duration-500`} style={imageStyle} onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>}
|
||||
{isLocal && img && <Image src={img} alt={alt || ""} class={`${imageClass} image-content`} style={imageStyle}/>}
|
||||
{!isLocal && (
|
||||
imageFallbackConfig.enable && src.includes(imageFallbackConfig.originalDomain) ?
|
||||
<img src={isPublic ? url(src) : src} alt={alt || ""} class={`${imageClass} image-content opacity-0 transition-opacity duration-500`} style={imageStyle} onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';" onerror={`this.onerror=null; this.src='${(isPublic ? url(src) : src).replace(imageFallbackConfig.originalDomain, imageFallbackConfig.fallbackDomain)}';`}/> :
|
||||
<img src={isPublic ? url(src) : src} alt={alt || ""} class={`${imageClass} image-content opacity-0 transition-opacity duration-500`} style={imageStyle} onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
||||
<img src={isPublic ? url(src) : src} alt={alt || ""} class={`${imageClass} image-content`} style={imageStyle} onerror={`this.onerror=null; this.src='${(isPublic ? url(src) : src).replace(imageFallbackConfig.originalDomain, imageFallbackConfig.fallbackDomain)}';`}/> :
|
||||
<img src={isPublic ? url(src) : src} alt={alt || ""} class={`${imageClass} image-content`} style={imageStyle}/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.loading-bar {
|
||||
transition: opacity 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes loading-progress {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(400%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-loading-progress {
|
||||
animation: loading-progress 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.image-content {
|
||||
transition: transform 0.3s ease-out, opacity 0.5s ease-out;
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
.image-wrapper:hover .image-content {
|
||||
|
||||
@@ -6,10 +6,7 @@ const config = profileConfig;
|
||||
---
|
||||
<div class="card-base p-3 border border-black/10 dark:border-white/10">
|
||||
<div class="relative mx-auto mt-1 lg:mx-0 lg:mt-0 mb-3 max-w-[12rem] lg:max-w-none rounded-xl overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
||||
</div>
|
||||
<img src={config.avatar} alt="Profile Image of the Author" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
||||
<img src={config.avatar} alt="Profile Image of the Author" class="w-full h-full object-cover transition duration-500" />
|
||||
</div>
|
||||
<div class="px-2">
|
||||
<div class="font-bold text-xl text-center mb-1 dark:text-neutral-50 transition">{config.name}</div>
|
||||
@@ -52,19 +49,6 @@ const config = profileConfig;
|
||||
.loading-bar {
|
||||
transition: opacity 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes loading-progress {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(400%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-loading-progress {
|
||||
animation: loading-progress 1.5s ease-in-out infinite;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script define:vars={{ umamiConfig}}>
|
||||
|
||||
@@ -82,7 +82,7 @@ const bannerOffset =
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang={siteLang} class="bg-[var(--page-bg)] transition text-[12px] md:text-[16px]"
|
||||
<html lang={siteLang} class="bg-[var(--page-bg)] transition text-[12px] md:text-[16px] dark"
|
||||
data-overlayscrollbars-initialize> <!-- 手机端适配 -->
|
||||
|
||||
<head>
|
||||
@@ -136,21 +136,21 @@ const bannerOffset =
|
||||
localStorage.setItem('theme', DARK_MODE);
|
||||
} else {
|
||||
// Load the theme from local storage
|
||||
const theme = localStorage.getItem('theme') || AUTO_MODE;
|
||||
switch (theme) {
|
||||
case LIGHT_MODE:
|
||||
document.documentElement.classList.remove('dark');
|
||||
break
|
||||
case DARK_MODE:
|
||||
const theme = localStorage.getItem('theme') || DARK_MODE;
|
||||
switch (theme) {
|
||||
case LIGHT_MODE:
|
||||
document.documentElement.classList.remove('dark');
|
||||
break
|
||||
case DARK_MODE:
|
||||
document.documentElement.classList.add('dark');
|
||||
break
|
||||
case AUTO_MODE:
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
document.documentElement.classList.add('dark');
|
||||
break
|
||||
case AUTO_MODE:
|
||||
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the hue from local storage
|
||||
@@ -161,71 +161,14 @@ const bannerOffset =
|
||||
let offset = Math.floor(window.innerHeight * (BANNER_HEIGHT_EXTEND / 100));
|
||||
offset = offset - offset % 4;
|
||||
document.documentElement.style.setProperty('--banner-height-extend', `${offset}px`);
|
||||
|
||||
// // Background image loading detection
|
||||
// const bgUrl = getComputedStyle(document.documentElement).getPropertyValue('--bg-url').trim();
|
||||
// const bgEnable = getComputedStyle(document.documentElement).getPropertyValue('--bg-enable').trim();
|
||||
|
||||
// if (bgUrl && bgUrl !== 'none' && bgEnable === '1') {
|
||||
// const img = new Image();
|
||||
// const urlMatch = bgUrl.match(/url\(["']?([^"')]+)["']?\)/);
|
||||
// if (urlMatch) {
|
||||
// img.onload = function() {
|
||||
// // 背景图片完全加载后,显示背景并启用卡片透明效果
|
||||
// document.body.classList.add('bg-loaded');
|
||||
// document.documentElement.style.setProperty('--card-bg', 'var(--card-bg-transparent)');
|
||||
// document.documentElement.style.setProperty('--float-panel-bg', 'var(--float-panel-bg-transparent)');
|
||||
// };
|
||||
// img.onerror = function() {
|
||||
// // Keep cards opaque if background image fails to load
|
||||
// console.warn('Background image failed to load, keeping cards opaque');
|
||||
// };
|
||||
// img.src = urlMatch[1];
|
||||
// }
|
||||
// }
|
||||
|
||||
// Random Background Image Integration
|
||||
// This waits for the external script to define window.getRandomPicH
|
||||
/*
|
||||
function setRandomBackground() {
|
||||
// Check if the external random pic function is available
|
||||
if (typeof window.getRandomPicH === 'function') {
|
||||
const bgUrl = window.getRandomPicH();
|
||||
const bgBox = document.getElementById('bg-box');
|
||||
if (bgBox && bgUrl) {
|
||||
console.log('Setting random background:', bgUrl);
|
||||
const img = new Image();
|
||||
img.onload = function() {
|
||||
bgBox.style.backgroundImage = `url('${bgUrl}')`;
|
||||
bgBox.classList.add('loaded');
|
||||
bgBox.classList.add('random-loaded'); // Add specific class
|
||||
console.log('Random background loaded successfully');
|
||||
|
||||
// Set CSS variables for transparency effects
|
||||
document.documentElement.style.setProperty('--card-bg', 'var(--card-bg-transparent)');
|
||||
document.documentElement.style.setProperty('--float-panel-bg', 'var(--float-panel-bg-transparent)');
|
||||
};
|
||||
img.onerror = function() {
|
||||
console.error('Failed to load random background image:', bgUrl);
|
||||
};
|
||||
img.src = bgUrl;
|
||||
} else {
|
||||
console.warn('bgBox not found or bgUrl is empty', { bgBox, bgUrl });
|
||||
}
|
||||
} else {
|
||||
// Retry after a short delay if script is not yet loaded
|
||||
console.log('Waiting for getRandomPicH...');
|
||||
setTimeout(setRandomBackground, 500);
|
||||
}
|
||||
}
|
||||
// Start attempting to set background
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', setRandomBackground);
|
||||
} else {
|
||||
setRandomBackground();
|
||||
}
|
||||
*/
|
||||
</script>
|
||||
|
||||
<style define:vars={{ configHue }}>
|
||||
/* Fallback for no-js: Apply default theme hue */
|
||||
:root {
|
||||
--hue: var(--configHue);
|
||||
}
|
||||
</style>
|
||||
<style define:vars={{
|
||||
configHue,
|
||||
'page-width': `${PAGE_WIDTH}rem`,
|
||||
|
||||
@@ -30,10 +30,7 @@ const friends = Object.values(
|
||||
<a href={friend.url} target="_blank" class="friend-card">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="relative w-5 h-5 rounded overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
||||
</div>
|
||||
<img src={friend.avatar} loading="lazy" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" alt={`${friend.name}的头像`} onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
||||
<img src={friend.avatar} loading="lazy" class="w-full h-full object-cover transition-opacity duration-500" alt={`${friend.name}的头像`} />
|
||||
</div>
|
||||
<div class="font-bold text-black dark:text-white">{friend.name}</div>
|
||||
</div>
|
||||
@@ -79,21 +76,4 @@ const friends = Object.values(
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 0.15s;
|
||||
}
|
||||
|
||||
.loading-bar {
|
||||
transition: opacity 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes loading-progress {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(400%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-loading-progress {
|
||||
animation: loading-progress 1.5s ease-in-out infinite;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -262,56 +262,9 @@ const jsonLd = {
|
||||
</style>
|
||||
|
||||
<script define:vars={{ siteConfig }}>
|
||||
// 图片加载动画处理
|
||||
// 图片加载处理 (仅用于图片回退逻辑)
|
||||
function setupImageLoading() {
|
||||
const markdownContent = document.querySelector('.markdown-content');
|
||||
if (!markdownContent) return;
|
||||
|
||||
const images = markdownContent.querySelectorAll('img');
|
||||
|
||||
images.forEach(img => {
|
||||
// 跳过已经处理过的图片
|
||||
if (img.parentElement.classList.contains('image-loading-wrapper')) return;
|
||||
|
||||
// 创建包裹容器
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'relative image-loading-wrapper rounded-xl overflow-hidden my-4';
|
||||
wrapper.style.setProperty('--theme-hue', siteConfig.themeColor.hue);
|
||||
|
||||
// 创建加载条
|
||||
const loadingBar = document.createElement('div');
|
||||
loadingBar.className = 'loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden';
|
||||
loadingBar.innerHTML = `<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>`;
|
||||
|
||||
// 插入DOM
|
||||
img.parentNode.insertBefore(wrapper, img);
|
||||
wrapper.appendChild(loadingBar);
|
||||
wrapper.appendChild(img);
|
||||
|
||||
// 设置图片初始状态
|
||||
img.style.opacity = '0';
|
||||
img.style.transition = 'opacity 0.5s ease-out';
|
||||
loadingBar.style.transition = 'opacity 0.5s ease-out';
|
||||
|
||||
// 处理加载完成
|
||||
const handleLoad = () => {
|
||||
img.style.opacity = '1';
|
||||
loadingBar.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
loadingBar.remove();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
if (img.complete) {
|
||||
handleLoad();
|
||||
} else {
|
||||
img.onload = handleLoad;
|
||||
img.onerror = () => {
|
||||
loadingBar.remove();
|
||||
img.style.opacity = '1';
|
||||
};
|
||||
}
|
||||
});
|
||||
// 保留此函数用于将来的其他处理,或者彻底删除
|
||||
}
|
||||
|
||||
// 初始化
|
||||
@@ -376,19 +329,6 @@ const jsonLd = {
|
||||
</script>
|
||||
|
||||
<style is:global>
|
||||
@keyframes loading-progress {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(400%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-loading-progress {
|
||||
animation: loading-progress 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* 确保包裹容器继承原图的圆角等样式 */
|
||||
.markdown-content img {
|
||||
margin: 0 !important; /* 让wrapper来控制margin */
|
||||
|
||||
@@ -44,10 +44,7 @@ const sponsors = Object.values(
|
||||
</div>
|
||||
<div class="qr-code-placeholder">
|
||||
<div class="relative w-48 h-48 mx-auto rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
||||
</div>
|
||||
<img src="/sponsors/alipay.svg" alt="支付宝二维码" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
||||
<img src="/sponsors/alipay.svg" alt="支付宝二维码" class="w-full h-full object-cover transition duration-500" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,10 +62,7 @@ const sponsors = Object.values(
|
||||
</div>
|
||||
<div class="qr-code-placeholder">
|
||||
<div class="relative w-48 h-48 mx-auto rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
||||
</div>
|
||||
<img src="/sponsors/wechat.svg" alt="微信支付二维码" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
||||
<img src="/sponsors/wechat.svg" alt="微信支付二维码" class="w-full h-full object-cover transition duration-500" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -129,10 +123,7 @@ const sponsors = Object.values(
|
||||
<div class="w-10 h-10 rounded-lg flex items-center justify-center overflow-hidden">
|
||||
{sponsor.avatar ? (
|
||||
<div class="relative w-full h-full rounded-lg overflow-hidden" style={`--theme-hue: ${siteConfig.themeColor.hue}`}>
|
||||
<div class="loading-bar absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-1 bg-gray-200 dark:bg-gray-700 z-10 rounded-full overflow-hidden">
|
||||
<div class="loading-progress h-full w-8 bg-[oklch(0.70_0.14_var(--theme-hue))] animate-loading-progress rounded-full"></div>
|
||||
</div>
|
||||
<img src={sponsor.avatar} alt={`${sponsor.name}的头像`} loading="lazy" class="w-full h-full object-cover opacity-0 transition-opacity duration-500" onload="this.style.opacity='1'; this.parentElement.querySelector('.loading-bar').style.opacity='0';"/>
|
||||
<img src={sponsor.avatar} alt={`${sponsor.name}的头像`} loading="lazy" class="w-full h-full object-cover transition duration-500" />
|
||||
</div>
|
||||
) : (
|
||||
<Icon name="material-symbols:person" class="text-gray-500 dark:text-gray-400 text-[1.2rem]" />
|
||||
@@ -199,23 +190,6 @@ const sponsors = Object.values(
|
||||
color: var(--primary);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.loading-bar {
|
||||
transition: opacity 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes loading-progress {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(400%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-loading-progress {
|
||||
animation: loading-progress 1.5s ease-in-out infinite;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
Reference in New Issue
Block a user