fixed 图片懒加载bug

This commit is contained in:
Vaica committed 2026-02-02 20:38:58 +08:00
1 parent 819b6d6e85
commit f8730d09e6
6 files changed
+216 -85

No files matched your search

+40 -12
View File
@@ -689,36 +689,49 @@ ul {
}
.header-info {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start; /* Changed to flex-start to align with text */
flex-direction: column; /* Stack vertically */
align-content: flex-end; /* Push to bottom */
justify-content: flex-end; /* Push to bottom */
align-items: center; /* Center align horizontally */
margin-left: 10px;
height: 80px;
width: calc(100vw - 140px); /* Ensure container takes available space */
width: calc(100vw - 140px);
padding-bottom: 0px;
}
.header-social {
display: flex;
align-items: center;
flex-wrap: nowrap;
gap: 10px;
margin-bottom: 5px;
width: 100%; /* Take full width to allow centering */
justify-content: center; /* Center icons horizontally */
gap: 12px; /* Increased gap for better spacing */
margin-bottom: 2px; /* Add small space between rows */
margin-right: 0;
width: 100%;
justify-content: center; /* Center align icons */
height: 24px;
}
.header-social a {
margin: 0 !important;
display: flex;
align-items: center;
}
.header-bio {
display: block;
font-size: 0.85rem;
line-height: 24px;
min-height: 24px;
margin: 0;
opacity: 0.8;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%; /* Take full width */
text-align: center; /* Center the text */
width: 100%; /* Full width */
text-align: center; /* Center align text */
/* Typewriter Effect Cursor */
border-right: 2px solid transparent; /* Hidden by default, toggled by JS if needed, or use ::after */
border-right: 2px solid transparent;
}
/* Cursor Animation Class */
@@ -743,7 +756,7 @@ ul {
margin-bottom: 0;
text-align: center;
/* Reset gap for social icons as they rely on margin */
gap: 0;
gap: 2;
}
.header-social a {
@@ -4687,6 +4700,21 @@ html[data-theme="light"] .atk-loading-spinner svg circle {
border-color: #333;
}
/* Lazy Load Animation */
.lazyload {
opacity: 0;
transform: translateY(30px); /* 稍微增加位移距离,增强上浮感 */
filter: blur(5px); /* 减少模糊,避免过于影响性能 */
transition: opacity 0.8s ease-out, transform 0.8s cubic-bezier(0.215, 0.61, 0.355, 1), filter 0.8s ease-out; /* 使用 ease-out 和自定义贝塞尔曲线,模拟自然惯性 */
will-change: opacity, transform; /* 移除 filter 的 will-change 以节省内存 */
}
.lazyload.lazy-loaded {
opacity: 1;
transform: translateY(0);
filter: blur(0);
}
[data-theme="dark"] .ai-comment-card .atk-content p {
color: var(--text-content-dark-color);
}
+4 -3
View File
@@ -8,9 +8,10 @@ document.addEventListener('DOMContentLoaded', function() {
// 文章图片懒加载 (优先初始化,防止其他模块调用时出错)
if (typeof lazyLoadInit === 'function') {
lazyLoadInit({
offsetBottom: 800,
offsetTopm: 800,
showTime: 1100
offsetBottom: 50,
offsetTopm: 50,
showTime: 1100,
queueInterval: 100
});
} else {
console.warn('lazyLoadInit is not defined');
+93 -46
View File
@@ -1,96 +1,143 @@
(function() {
// Default configuration
var defaults = {
showTime: 800,
offsetBottom: 0,
offsetTopm: 50,
onLoadBackEnd: function (index, dom) { },
onLoadBackStart: function (index, dom) { }
offsetBottom: 100, // Distance from bottom to start loading
showTime: 1100, // Transition duration (ms)
queueInterval: 200 // Time between showing successive images in queue
};
var observer;
var imageQueue = []; // Queue for images waiting to be shown
var isProcessingQueue = false;
function init(setting) {
// Merge settings
defaults = Object.assign({}, defaults, setting || {});
// Reset observer for PJAX support
// Reset queue
imageQueue = [];
isProcessingQueue = false;
// Disconnect previous observer if exists (for PJAX)
if (observer) {
observer.disconnect();
observer = null;
}
// Check for IntersectionObserver support
if (!window.IntersectionObserver) {
loadAllImages();
return;
}
// Initialize IntersectionObserver
observer = new IntersectionObserver(function(entries, self) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var img = entry.target;
showImg(img);
// Add to queue instead of loading immediately
addToQueue(img);
// Stop observing this image once it's triggered
self.unobserve(img);
}
});
}, {
rootMargin: defaults.offsetTopm + "px 0px " + defaults.offsetBottom + "px 0px"
rootMargin: "0px 0px " + defaults.offsetBottom + "px 0px",
threshold: 0.01
});
processImages();
observeImages();
}
function processImages() {
if (!observer) {
init(); // Auto-initialize if not ready
function addToQueue(img) {
// Avoid duplicates
if (!imageQueue.includes(img)) {
imageQueue.push(img);
processQueue();
}
// Expanded selector to catch more images
var images = document.querySelectorAll('img.lazyload, img:not(.blog-img):not([data-comp])');
}
function processQueue() {
if (isProcessingQueue) return;
if (imageQueue.length === 0) return;
isProcessingQueue = true;
var img = imageQueue.shift();
loadImage(img, function() {
// After this image starts showing (or fails), process next after delay
setTimeout(function() {
isProcessingQueue = false;
processQueue();
}, defaults.queueInterval);
});
}
function observeImages() {
var images = document.querySelectorAll('img.lazyload, .post-content img:not(.lazy-loaded)');
images.forEach(function(img) {
// Check if already processed or has data-lazy-src
if (img.classList.contains('lazy-loaded')) return;
// Update transition duration based on settings
if (defaults.showTime) {
// We'll set this via inline style or rely on CSS class if it matches default
// But for full control, let's set it
img.style.transitionDuration = (defaults.showTime / 1000) + 's';
}
if (img.getAttribute('data-lazy-src')) {
// Already setup for lazy load, just observe
observer.observe(img);
} else if (img.getAttribute('src')) {
// Convert to lazy load
var src = img.getAttribute('src');
img.setAttribute('data-lazy-src', src);
img.setAttribute('src', 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==');
observer.observe(img);
}
});
}
function showImg(dom) {
if (dom.getAttribute('data-comp')) return;
dom.setAttribute('data-comp', 'true');
var src = dom.getAttribute('data-lazy-src');
if (!src) return;
function loadImage(img, callback) {
var src = img.getAttribute('data-lazy-src');
if (!src) {
if (callback) callback();
return;
}
// Create a temporary image to preload
var temp = new Image();
temp.onload = function() {
// Prepare for transition
dom.style.opacity = 0;
dom.style.transition = "opacity " + (defaults.showTime / 1000) + "s ease-in-out";
var onComplete = function() {
// Swap source
dom.setAttribute('src', src);
img.src = src;
// Force reflow
void dom.offsetWidth;
// Fade in
dom.style.opacity = 1;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
img.classList.add('lazy-loaded');
img.removeAttribute('data-lazy-src');
// Execute callback immediately after starting animation logic
if (callback) callback();
});
});
};
temp.onload = onComplete;
temp.onerror = function() {
// On error, show anyway
dom.setAttribute('src', src);
dom.style.opacity = 1;
// Fallback
img.src = src;
requestAnimationFrame(() => {
img.classList.add('lazy-loaded');
if (callback) callback();
});
};
temp.src = src;
}
function tryAgain() {
processImages();
function loadAllImages() {
var images = document.querySelectorAll('img.lazyload');
images.forEach(function(img) {
loadImage(img);
});
}
window.lazyLoadInit = init;
window.lazyLoadAgain = tryAgain;
window.lazyLoadRefresh = observeImages;
})();
+4 -3
View File
@@ -67,9 +67,10 @@ document.addEventListener("pjax:success", function () {
lazyLoadInit({
// coverColor: "white",
// coverDiv: "<div style='display: flex; justify-content: center; align-items: center; height: 200px; color: #000000;'><span>优世界·一个记录生活点滴的小站</span></div>",
offsetBottom: 800,
offsetTopm: 800,
showTime: 1100
offsetBottom: 50,
offsetTopm: 50,
showTime: 1100,
queueInterval: 100
});
}
// 激活文章图片灯箱
+73 -21
View File
@@ -348,34 +348,86 @@ function initInlineSearch() {
}
}
// Reset text content initially but keep it ready
// Pre-fill first character to avoid empty bubble on mobile (where CSS forces visibility)
if (text.length > 0) {
searchHintText.textContent = text.charAt(0);
} else {
searchHintText.textContent = '';
}
// Show wrapper initially
setTimeout(function() {
// Add visible class (triggers fade in on desktop)
var typeInterval;
var hideTimeout;
function runTypewriter(str, callback) {
if (typeInterval) clearInterval(typeInterval);
if (hideTimeout) clearTimeout(hideTimeout);
// Ensure visible
searchHintWrapper.classList.add('visible');
// Typewriter effect
var i = 1;
var typeInterval = setInterval(function() {
if (i >= text.length) {
// Pre-fill first char
if (str.length > 0) {
searchHintText.textContent = str.charAt(0);
}
typeInterval = setInterval(function() {
if (i >= str.length) {
clearInterval(typeInterval);
// Hide after 8 seconds (give more time to read greetings)
setTimeout(function() {
searchHintWrapper.classList.remove('visible');
}, 8000);
if (callback) callback();
return;
}
searchHintText.textContent = text.substring(0, i + 1);
searchHintText.textContent = str.substring(0, i + 1);
i++;
}, 100);
}, 500);
}
// Check session storage for Jiaotailang tip
if (!sessionStorage.getItem('jiaotailang_shown')) {
// Initial Delay
setTimeout(function() {
// Step 1: Show Greeting
runTypewriter(text, function() {
// Animation Finished
// Step 2: Check Mobile Logic
if (window.isMobile && window.isMobile()) {
// Wait 2s then show secret hint
hideTimeout = setTimeout(function() {
var secretHint = "悄悄咪咪告诉你 点击随笔开始搜索";
runTypewriter(secretHint, function() {
// Finished secret hint
sessionStorage.setItem('jiaotailang_shown', 'true');
// Hide after 5s
hideTimeout = setTimeout(function() {
searchHintWrapper.classList.remove('visible');
}, 5000);
});
}, 2000);
} else {
// Desktop: Just hide after 8s
sessionStorage.setItem('jiaotailang_shown', 'true');
hideTimeout = setTimeout(function() {
searchHintWrapper.classList.remove('visible');
}, 8000);
}
});
}, 500);
} else {
// If already shown, set full text but don't auto-show
searchHintText.textContent = text;
}
// --- Hover Logic (Desktop) ---
if (!window.isMobile || !window.isMobile()) {
header.addEventListener('mouseenter', function() {
// Stop any running animations
if (typeInterval) clearInterval(typeInterval);
if (hideTimeout) clearTimeout(hideTimeout);
searchHintWrapper.classList.add('visible');
searchHintText.textContent = "点击随笔,开始搜索";
});
header.addEventListener('mouseleave', function() {
// Simply hide when leaving
searchHintWrapper.classList.remove('visible');
// Optional: Reset text to greeting in case it's shown again by some other logic?
// But mostly it will be triggered by hover again.
});
}
}
}