From 1d14bca0ac0459c281e018d497e8e6b69a4fad28 Mon Sep 17 00:00:00 2001 From: Vaica <94612053+zqlit@users.noreply.github.com> Date: Mon, 2 Feb 2026 20:38:58 +0800 Subject: [PATCH] =?UTF-8?q?fixed=20=E5=9B=BE=E7=89=87=E6=87=92=E5=8A=A0?= =?UTF-8?q?=E8=BD=BDbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026/2026-02-03-blog-refurbish/index.md | 2 + themes/Ying/assets/css/main.css | 52 +++++-- themes/Ying/assets/js/main.js | 7 +- themes/Ying/assets/js/modules/lazyload.js | 139 ++++++++++++------ themes/Ying/assets/js/modules/mypjax.js | 7 +- themes/Ying/assets/js/modules/search.js | 94 +++++++++--- 6 files changed, 216 insertions(+), 85 deletions(-) diff --git a/content/post/2026/2026-02-03-blog-refurbish/index.md b/content/post/2026/2026-02-03-blog-refurbish/index.md index e8758db4..e873fba3 100644 --- a/content/post/2026/2026-02-03-blog-refurbish/index.md +++ b/content/post/2026/2026-02-03-blog-refurbish/index.md @@ -44,6 +44,8 @@ ai_comment: >- * **蕉太狼温馨提示**:在首页右下角加了一个小小的“蕉太狼”挂件。它会在早晨问好,深夜催睡。虽然只是简单的几行代码逻辑,但让博客多了一点“人情味”。 +* **丝滑的图片加载**:给文章里的图片加了个“懒加载”动画。以前图片是“刷”的一下出来的,现在是当你滑到它的时候,它会优雅地从下往上浮现出来,那种顺滑的感觉,就像是德芙巧克力一样(夸张了哈),反正我是盯着看了好几遍。 + ## 效果展示 旧样式 diff --git a/themes/Ying/assets/css/main.css b/themes/Ying/assets/css/main.css index b6a9ed5f..9744de18 100644 --- a/themes/Ying/assets/css/main.css +++ b/themes/Ying/assets/css/main.css @@ -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); } diff --git a/themes/Ying/assets/js/main.js b/themes/Ying/assets/js/main.js index 78ab5252..5c69ee16 100644 --- a/themes/Ying/assets/js/main.js +++ b/themes/Ying/assets/js/main.js @@ -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'); diff --git a/themes/Ying/assets/js/modules/lazyload.js b/themes/Ying/assets/js/modules/lazyload.js index 1a23f555..6f1e9984 100644 --- a/themes/Ying/assets/js/modules/lazyload.js +++ b/themes/Ying/assets/js/modules/lazyload.js @@ -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; })(); diff --git a/themes/Ying/assets/js/modules/mypjax.js b/themes/Ying/assets/js/modules/mypjax.js index 3913d707..f41a174a 100644 --- a/themes/Ying/assets/js/modules/mypjax.js +++ b/themes/Ying/assets/js/modules/mypjax.js @@ -67,9 +67,10 @@ document.addEventListener("pjax:success", function () { lazyLoadInit({ // coverColor: "white", // coverDiv: "