166 lines
5.0 KiB
JavaScript
166 lines
5.0 KiB
JavaScript
// Initial Call
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// 文章图片灯箱
|
|
if (window.ViewImage) {
|
|
ViewImage.init('.post-content img');
|
|
}
|
|
|
|
// 灯箱增强:滚动关闭 + fade scale 退回动画
|
|
(function() {
|
|
var clickedImg = null;
|
|
|
|
document.addEventListener('click', function(e) {
|
|
var img = e.target.closest('.post-content img');
|
|
if (img) clickedImg = img;
|
|
}, true);
|
|
|
|
function closeLightbox() {
|
|
var lb = document.querySelector('.view-image');
|
|
if (!lb) return;
|
|
|
|
// 用 UIkit 内置动画关闭
|
|
if (window.UIkit && UIkit.animate) {
|
|
UIkit.animate(lb, 'uk-animation-fade uk-animation-fast');
|
|
setTimeout(function() { lb.remove(); }, 300);
|
|
} else {
|
|
lb.classList.add('view-image__out');
|
|
setTimeout(function() { lb.remove(); }, 290);
|
|
}
|
|
}
|
|
|
|
// 拦截关闭按钮
|
|
document.addEventListener('click', function(e) {
|
|
var lb = e.target.closest('.view-image');
|
|
if (!lb) return;
|
|
var isClose = e.target.closest('.view-image-close') || e.target.closest('.view-image-close__full');
|
|
if (!isClose) return;
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
closeLightbox();
|
|
}, true);
|
|
|
|
// 滚动关闭
|
|
var lastScrollY = window.scrollY;
|
|
window.addEventListener('scroll', function() {
|
|
var lb = document.querySelector('.view-image');
|
|
if (!lb) { lastScrollY = window.scrollY; return; }
|
|
if (Math.abs(window.scrollY - lastScrollY) > 15) {
|
|
lastScrollY = window.scrollY;
|
|
closeLightbox();
|
|
}
|
|
}, { passive: true });
|
|
})();
|
|
|
|
// 文章图片懒加载 (优先初始化,防止其他模块调用时出错)
|
|
if (typeof lazyLoadInit === 'function') {
|
|
lazyLoadInit({
|
|
offsetBottom: 50,
|
|
offsetTopm: 50,
|
|
showTime: 1100,
|
|
queueInterval: 100
|
|
});
|
|
} else {
|
|
console.warn('lazyLoadInit is not defined');
|
|
}
|
|
|
|
// 初始化各个模块
|
|
if (window.initLoader) window.initLoader();
|
|
if (window.initFloatingTools) window.initFloatingTools();
|
|
if (window.initSearch) window.initSearch();
|
|
if (window.initArtalk) window.initArtalk();
|
|
|
|
// New Utils Init
|
|
if (window.initThemeToggle) window.initThemeToggle();
|
|
if (window.initCodeFold) window.initCodeFold();
|
|
if (window.initCodeCopy) window.initCodeCopy();
|
|
if (window.initParagraphComments) window.initParagraphComments();
|
|
if (window.initInfiniteScroll && window.enableInfiniteScroll) window.initInfiniteScroll();
|
|
|
|
// Initialize Typewriter Effect for Mobile Header
|
|
initTypewriter();
|
|
|
|
// Image frame scroll reveal
|
|
initImageFrameReveal();
|
|
});
|
|
|
|
/**
|
|
* Typewriter Effect for Mobile Header Bio
|
|
*/
|
|
function initTypewriter() {
|
|
// Only run on mobile or if the element is visible
|
|
const bioElement = document.querySelector('.header-bio');
|
|
if (!bioElement) return;
|
|
|
|
// Check if we are on mobile (matching CSS media query)
|
|
const isMobile = window.matchMedia('(max-width: 768px)').matches;
|
|
if (!isMobile) return;
|
|
|
|
const originalText = bioElement.innerText.trim();
|
|
if (!originalText) return;
|
|
|
|
// Clear text initially
|
|
bioElement.innerText = '';
|
|
bioElement.classList.add('typing');
|
|
|
|
let i = 0;
|
|
const speed = 100; // Typing speed in ms
|
|
|
|
function typeWriter() {
|
|
if (i < originalText.length) {
|
|
bioElement.innerText += originalText.charAt(i);
|
|
i++;
|
|
setTimeout(typeWriter, speed);
|
|
} else {
|
|
// Typing finished, remove cursor after a delay?
|
|
// bioElement.classList.remove('typing');
|
|
// Keep blinking cursor for effect
|
|
}
|
|
}
|
|
|
|
// Start typing with a small delay
|
|
setTimeout(typeWriter, 500);
|
|
}
|
|
|
|
/**
|
|
* Scroll-triggered reveal for sen-image-frame
|
|
*/
|
|
var senFrameObserver = null;
|
|
|
|
function initImageFrameReveal() {
|
|
var frames = document.querySelectorAll('.sen-image-frame');
|
|
if (!frames.length) return;
|
|
|
|
if (!window.IntersectionObserver) {
|
|
frames.forEach(function(frame) {
|
|
frame.classList.add('is-visible');
|
|
});
|
|
return;
|
|
}
|
|
|
|
frames.forEach(function(frame) {
|
|
frame.classList.add('reveal-pending');
|
|
});
|
|
|
|
if (senFrameObserver) {
|
|
senFrameObserver.disconnect();
|
|
}
|
|
|
|
senFrameObserver = new IntersectionObserver(function(entries) {
|
|
entries.forEach(function(entry) {
|
|
if (entry.isIntersecting) {
|
|
entry.target.classList.add('is-visible');
|
|
senFrameObserver.unobserve(entry.target);
|
|
}
|
|
});
|
|
}, {
|
|
rootMargin: "0px 0px 50px 0px",
|
|
threshold: 0.08
|
|
});
|
|
|
|
frames.forEach(function(frame) {
|
|
senFrameObserver.observe(frame);
|
|
});
|
|
}
|
|
|
|
window.initImageFrameReveal = initImageFrameReveal;
|