Multi-type publish/VIP CTA in nav, zibll-like _win runtime bridge for lightbox flags, and floating shop_cart/pay_vip commerce buttons.
612 lines
22 KiB
JavaScript
612 lines
22 KiB
JavaScript
/**
|
||
* AKSRT Enhancements — 全局 UI 增强
|
||
*
|
||
* 包含:Toast 通知、图片灯箱、滚动方向感知
|
||
*
|
||
* @package AKSRT
|
||
*/
|
||
|
||
(function () {
|
||
'use strict';
|
||
|
||
/* ============================================================
|
||
* 1. Toast 通知系统
|
||
* ============================================================ */
|
||
var toastContainer = null;
|
||
|
||
function ensureToastContainer() {
|
||
if (!toastContainer || !document.body.contains(toastContainer)) {
|
||
toastContainer = document.createElement('div');
|
||
toastContainer.className = 'aksrt-toast-container';
|
||
document.body.appendChild(toastContainer);
|
||
}
|
||
return toastContainer;
|
||
}
|
||
|
||
/**
|
||
* 显示 Toast 通知
|
||
*
|
||
* @param {string} message 消息文本
|
||
* @param {string} type 类型: success, info, warning, danger/error, loading
|
||
* @param {number} duration 显示时长(ms),0 表示不自动关闭
|
||
* @returns {Object} { dismiss: Function, update: Function }
|
||
*/
|
||
function showToast(message, type, duration) {
|
||
type = type || 'success';
|
||
if (type === 'error') type = 'danger';
|
||
duration = duration !== undefined ? duration : 3500;
|
||
if (duration > 0 && duration < 100) duration = duration * 1000;
|
||
|
||
var container = ensureToastContainer();
|
||
|
||
var icons = {
|
||
success: 'fas fa-check-circle',
|
||
info: 'fas fa-bell',
|
||
warning: 'fas fa-exclamation-circle',
|
||
danger: 'fas fa-times-circle',
|
||
loading: 'fas fa-spinner',
|
||
};
|
||
|
||
var el = document.createElement('div');
|
||
el.className = 'aksrt-toast aksrt-toast--' + type;
|
||
el.innerHTML =
|
||
'<span class="aksrt-toast__icon"><i class="' + (icons[type] || icons.info) + '"></i></span>' +
|
||
'<span class="aksrt-toast__text">' + message + '</span>';
|
||
|
||
container.appendChild(el);
|
||
|
||
var timer = null;
|
||
|
||
function dismiss() {
|
||
if (timer) clearTimeout(timer);
|
||
el.classList.add('is-dismissing');
|
||
setTimeout(function () {
|
||
if (el.parentNode) el.remove();
|
||
}, 300);
|
||
}
|
||
|
||
function update(newMessage, newType) {
|
||
if (newType) {
|
||
el.className = 'aksrt-toast aksrt-toast--' + newType;
|
||
var iconEl = el.querySelector('.aksrt-toast__icon i');
|
||
if (iconEl) iconEl.className = icons[newType] || icons.info;
|
||
}
|
||
var textEl = el.querySelector('.aksrt-toast__text');
|
||
if (textEl) textEl.textContent = newMessage;
|
||
|
||
if (newType !== 'loading' && duration > 0) {
|
||
if (timer) clearTimeout(timer);
|
||
timer = setTimeout(dismiss, duration);
|
||
}
|
||
}
|
||
|
||
el.addEventListener('click', dismiss);
|
||
|
||
if (type !== 'loading' && duration > 0) {
|
||
timer = setTimeout(dismiss, duration);
|
||
}
|
||
|
||
return { dismiss: dismiss, update: update };
|
||
}
|
||
|
||
// 暴露到全局
|
||
window.AksrtToast = showToast;
|
||
|
||
/* ============================================================
|
||
* 2. 图片灯箱 — zoom / thumbnails / slideshow / fullscreen /
|
||
* mousewheel / origin animation / smart download
|
||
* ============================================================ */
|
||
var lightboxEl = null;
|
||
var lightboxImg = null;
|
||
var lightboxCaption = null;
|
||
var lightboxCounter = null;
|
||
var lightboxThumbsWrap = null;
|
||
var currentGallery = [];
|
||
var currentIndex = 0;
|
||
var currentZoom = 1;
|
||
var autoplayTimer = null;
|
||
var isAutoplay = false;
|
||
var EXCLUDE_SEL = '.no-imgbox,.no-lightbox,.avatar,.img-icon,.avatar-badge,.smilie-icon,.aksrt-avatar,.aksrt-lazy-skeleton';
|
||
var TRIGGER_SEL = '.entry-content img, .wp-posts-content img, .aksrt-lightbox-trigger img, [data-aksrt-lightbox] img, .imgbox-container img, .comment-content .box-img img, a[data-imgbox] img';
|
||
var CONTAINER_SEL = '.entry-content, .wp-posts-content, .aksrt-lightbox-trigger, [data-aksrt-lightbox], .imgbox-container, .comment-content';
|
||
var MAX_ZOOM_DESKTOP = 2;
|
||
var MAX_ZOOM_MOBILE = 3;
|
||
|
||
function lightboxFlag(key, fallback) {
|
||
var w = window._win || (window.aksrtData && window.aksrtData.imgbox) || {};
|
||
if (w[key] === undefined || w[key] === null || w[key] === '') return fallback;
|
||
return w[key] === true || w[key] === 1 || w[key] === '1';
|
||
}
|
||
function lightboxEnabled() {
|
||
return lightboxFlag('imgbox', true);
|
||
}
|
||
|
||
|
||
function resolveFullUrl(img) {
|
||
var full = img.getAttribute('data-full-url') || img.getAttribute('data-src') || '';
|
||
if (full) return full;
|
||
var src = img.src || '';
|
||
// thumbnail → original: strip -NNNxNNN suffix
|
||
return src.replace(/-\d+x\d+(\.[a-z]+)$/i, '$1');
|
||
}
|
||
|
||
function isNoLightbox(img) {
|
||
if (img.closest(EXCLUDE_SEL)) return true;
|
||
// parent anchor that does NOT point to an image
|
||
var parentA = img.closest('a');
|
||
if (parentA) {
|
||
var href = parentA.getAttribute('href') || '';
|
||
if (href && !/\.(jpe?g|png|gif|webp|avif|svg|bmp)(\?|$)/i.test(href) && !parentA.hasAttribute('data-imgbox')) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function createLightbox() {
|
||
if (!lightboxEnabled()) return;
|
||
if (lightboxEl) return;
|
||
|
||
lightboxEl = document.createElement('div');
|
||
lightboxEl.className = 'aksrt-lightbox';
|
||
lightboxEl.innerHTML =
|
||
'<div class="aksrt-lightbox__toolbar">' +
|
||
'<span class="aksrt-lightbox__counter"></span>' +
|
||
'<button type="button" class="aksrt-lightbox__tool toggle-zoom" title="缩放"><i class="fas fa-search-plus"></i></button>' +
|
||
'<button type="button" class="aksrt-lightbox__tool toggle-thumbs" title="缩略图"><i class="fas fa-th"></i></button>' +
|
||
'<button type="button" class="aksrt-lightbox__tool toggle-play" title="幻灯片"><i class="fas fa-play"></i></button>' +
|
||
'<button type="button" class="aksrt-lightbox__tool toggle-full" title="全屏"><i class="fas fa-expand"></i></button>' +
|
||
'<button type="button" class="aksrt-lightbox__tool aksrt-lightbox__download" title="下载"><i class="fas fa-download"></i></button>' +
|
||
'<button type="button" class="aksrt-lightbox__tool aksrt-lightbox__close" title="关闭"><i class="fas fa-times"></i></button>' +
|
||
'</div>' +
|
||
'<button type="button" class="aksrt-lightbox__nav aksrt-lightbox__nav--prev" aria-label="上一张"><i class="fas fa-chevron-left"></i></button>' +
|
||
'<div class="aksrt-lightbox__stage"><img class="aksrt-lightbox__img" src="" alt=""></div>' +
|
||
'<button type="button" class="aksrt-lightbox__nav aksrt-lightbox__nav--next" aria-label="下一张"><i class="fas fa-chevron-right"></i></button>' +
|
||
'<div class="aksrt-lightbox__caption"></div>' +
|
||
'<div class="aksrt-lightbox__thumbs" hidden></div>';
|
||
|
||
document.body.appendChild(lightboxEl);
|
||
|
||
lightboxImg = lightboxEl.querySelector('.aksrt-lightbox__img');
|
||
lightboxCaption = lightboxEl.querySelector('.aksrt-lightbox__caption');
|
||
lightboxCounter = lightboxEl.querySelector('.aksrt-lightbox__counter');
|
||
lightboxThumbsWrap = lightboxEl.querySelector('.aksrt-lightbox__thumbs');
|
||
|
||
// Apply window._win imgbox feature flags
|
||
var zoomBtn = lightboxEl.querySelector('.toggle-zoom');
|
||
var thumbsBtn = lightboxEl.querySelector('.toggle-thumbs');
|
||
var playBtn = lightboxEl.querySelector('.toggle-play');
|
||
var fullBtn = lightboxEl.querySelector('.toggle-full');
|
||
var downBtn = lightboxEl.querySelector('.aksrt-lightbox__download');
|
||
if (zoomBtn) zoomBtn.hidden = !lightboxFlag('imgbox_zoom', true);
|
||
if (thumbsBtn) thumbsBtn.hidden = !lightboxFlag('imgbox_thumbs', true);
|
||
if (playBtn) playBtn.hidden = !lightboxFlag('imgbox_play', false);
|
||
if (fullBtn) fullBtn.hidden = !lightboxFlag('imgbox_full', true);
|
||
if (downBtn) downBtn.hidden = !lightboxFlag('imgbox_down', false);
|
||
|
||
// Close
|
||
lightboxEl.querySelector('.aksrt-lightbox__close').addEventListener('click', function (e) { e.stopPropagation(); closeLightbox(); });
|
||
lightboxEl.addEventListener('click', function (e) { if (e.target === lightboxEl || e.target.classList.contains('aksrt-lightbox__stage')) closeLightbox(); });
|
||
|
||
// Nav
|
||
lightboxEl.querySelector('.aksrt-lightbox__nav--prev').addEventListener('click', function (e) { e.stopPropagation(); navigateLightbox(-1); });
|
||
lightboxEl.querySelector('.aksrt-lightbox__nav--next').addEventListener('click', function (e) { e.stopPropagation(); navigateLightbox(1); });
|
||
|
||
// Keyboard
|
||
document.addEventListener('keydown', function (e) {
|
||
if (!lightboxEl.classList.contains('is-open')) return;
|
||
if (e.key === 'Escape') closeLightbox();
|
||
if (e.key === 'ArrowLeft') navigateLightbox(-1);
|
||
if (e.key === 'ArrowRight') navigateLightbox(1);
|
||
});
|
||
|
||
// Mousewheel nav
|
||
lightboxEl.addEventListener('wheel', function (e) {
|
||
if (!lightboxEl.classList.contains('is-open')) return;
|
||
if (currentZoom > 1) return; // don't nav when zoomed
|
||
e.preventDefault();
|
||
if (e.deltaY > 0) navigateLightbox(1);
|
||
else navigateLightbox(-1);
|
||
}, { passive: false });
|
||
|
||
// Image click → toggle zoom
|
||
lightboxImg.addEventListener('click', function (e) { e.stopPropagation(); toggleZoom(); });
|
||
|
||
// Double-click → zoom in
|
||
lightboxImg.addEventListener('dblclick', function (e) {
|
||
e.stopPropagation();
|
||
var maxZoom = window.innerWidth < 768 ? MAX_ZOOM_MOBILE : MAX_ZOOM_DESKTOP;
|
||
if (currentZoom < maxZoom) setZoom(maxZoom);
|
||
else setZoom(1);
|
||
});
|
||
|
||
// Pinch zoom (mobile)
|
||
var pinchStart = 0;
|
||
lightboxEl.addEventListener('touchstart', function (e) {
|
||
if (e.touches.length === 2) {
|
||
pinchStart = Math.hypot(
|
||
e.touches[1].clientX - e.touches[0].clientX,
|
||
e.touches[1].clientY - e.touches[0].clientY
|
||
);
|
||
}
|
||
}, { passive: true });
|
||
|
||
lightboxEl.addEventListener('touchmove', function (e) {
|
||
if (e.touches.length === 2 && pinchStart > 0) {
|
||
var dist = Math.hypot(
|
||
e.touches[1].clientX - e.touches[0].clientX,
|
||
e.touches[1].clientY - e.touches[0].clientY
|
||
);
|
||
var maxZoom = window.innerWidth < 768 ? MAX_ZOOM_MOBILE : MAX_ZOOM_DESKTOP;
|
||
var newZoom = Math.min(maxZoom, Math.max(1, currentZoom * (dist / pinchStart)));
|
||
setZoom(newZoom);
|
||
pinchStart = dist;
|
||
}
|
||
}, { passive: true });
|
||
|
||
lightboxEl.addEventListener('touchend', function () { pinchStart = 0; }, { passive: true });
|
||
|
||
// Touch swipe/pull-dismiss (skip when zoomed)
|
||
var touchStartY = 0, touchStartX = 0, isSwiping = false;
|
||
lightboxEl.addEventListener('touchstart', function (e) {
|
||
if (e.touches.length !== 1 || currentZoom > 1.05) return;
|
||
touchStartY = e.touches[0].clientY;
|
||
touchStartX = e.touches[0].clientX;
|
||
isSwiping = false;
|
||
}, { passive: true });
|
||
|
||
lightboxEl.addEventListener('touchmove', function (e) {
|
||
if (e.touches.length !== 1 || currentZoom > 1.05) return;
|
||
var dy = e.touches[0].clientY - touchStartY;
|
||
var dx = e.touches[0].clientX - touchStartX;
|
||
if (Math.abs(dy) > Math.abs(dx) && dy > 30) {
|
||
isSwiping = true;
|
||
var opacity = Math.max(0.2, (150 - dy) / 80);
|
||
lightboxImg.style.transform = 'translate3d(0, ' + dy + 'px, 0) scale(' + currentZoom + ')';
|
||
lightboxImg.style.opacity = String(Math.min(1, opacity));
|
||
}
|
||
}, { passive: true });
|
||
|
||
lightboxEl.addEventListener('touchend', function () {
|
||
if (isSwiping) {
|
||
closeLightbox();
|
||
lightboxImg.style.transform = '';
|
||
lightboxImg.style.opacity = '';
|
||
}
|
||
isSwiping = false;
|
||
}, { passive: true });
|
||
|
||
// Download
|
||
lightboxEl.querySelector('.aksrt-lightbox__download').addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
var item = currentGallery[currentIndex];
|
||
if (!item || !item.src) return;
|
||
var a = document.createElement('a');
|
||
var fullSrc = item.fullSrc || item.src;
|
||
a.href = fullSrc;
|
||
a.download = fullSrc.substring(fullSrc.lastIndexOf('/') + 1) || 'image';
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
a.remove();
|
||
});
|
||
|
||
// Zoom button
|
||
lightboxEl.querySelector('.toggle-zoom').addEventListener('click', function (e) { e.stopPropagation(); toggleZoom(); });
|
||
|
||
// Thumbnails toggle
|
||
lightboxEl.querySelector('.toggle-thumbs').addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
lightboxThumbsWrap.hidden = !lightboxThumbsWrap.hidden;
|
||
});
|
||
|
||
// Slideshow toggle
|
||
lightboxEl.querySelector('.toggle-play').addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
toggleAutoplay();
|
||
});
|
||
|
||
// Fullscreen
|
||
lightboxEl.querySelector('.toggle-full').addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
toggleFullscreen();
|
||
});
|
||
|
||
document.addEventListener('fullscreenchange', function () {
|
||
var icon = lightboxEl.querySelector('.toggle-full i');
|
||
if (document.fullscreenElement) {
|
||
lightboxEl.classList.add('full-screen');
|
||
icon.className = 'fas fa-compress';
|
||
} else {
|
||
lightboxEl.classList.remove('full-screen');
|
||
icon.className = 'fas fa-expand';
|
||
}
|
||
});
|
||
}
|
||
|
||
function setZoom(z) {
|
||
currentZoom = z;
|
||
lightboxImg.style.transform = 'scale(' + z + ')';
|
||
lightboxEl.classList.toggle('is-zoomed', z > 1);
|
||
}
|
||
|
||
function toggleZoom() {
|
||
var maxZoom = window.innerWidth < 768 ? MAX_ZOOM_MOBILE : MAX_ZOOM_DESKTOP;
|
||
setZoom(currentZoom > 1 ? 1 : maxZoom);
|
||
}
|
||
|
||
function toggleAutoplay() {
|
||
var icon = lightboxEl.querySelector('.toggle-play i');
|
||
if (isAutoplay) {
|
||
clearInterval(autoplayTimer);
|
||
isAutoplay = false;
|
||
icon.className = 'fas fa-play';
|
||
} else {
|
||
if (currentGallery.length < 2) return;
|
||
isAutoplay = true;
|
||
icon.className = 'fas fa-pause';
|
||
autoplayTimer = setInterval(function () { navigateLightbox(1); }, 3000);
|
||
}
|
||
}
|
||
|
||
function toggleFullscreen() {
|
||
var rfs = lightboxEl.requestFullscreen || lightboxEl.webkitRequestFullscreen || lightboxEl.msRequestFullscreen;
|
||
if (document.fullscreenElement || document.webkitFullscreenElement) {
|
||
(document.exitFullscreen || document.webkitExitFullscreen || document.msExitFullscreen).call(document);
|
||
} else if (rfs) {
|
||
rfs.call(lightboxEl);
|
||
}
|
||
}
|
||
|
||
function buildThumbnails() {
|
||
if (!lightboxThumbsWrap) return;
|
||
lightboxThumbsWrap.innerHTML = '';
|
||
currentGallery.forEach(function (item, i) {
|
||
var thumb = document.createElement('img');
|
||
thumb.src = item.src;
|
||
thumb.className = 'aksrt-lightbox__thumb' + (i === currentIndex ? ' is-active' : '');
|
||
thumb.addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
showLightboxImage(i);
|
||
});
|
||
lightboxThumbsWrap.appendChild(thumb);
|
||
});
|
||
}
|
||
|
||
function syncThumbActive() {
|
||
if (!lightboxThumbsWrap) return;
|
||
var thumbs = lightboxThumbsWrap.querySelectorAll('.aksrt-lightbox__thumb');
|
||
thumbs.forEach(function (t, i) { t.classList.toggle('is-active', i === currentIndex); });
|
||
var active = thumbs[currentIndex];
|
||
if (active) active.scrollIntoView({ inline: 'center', block: 'nearest', behavior: 'smooth' });
|
||
}
|
||
|
||
function openLightbox(src, caption, gallery, index, originEl) {
|
||
createLightbox();
|
||
|
||
currentGallery = gallery || [{ src: src, caption: caption || '' }];
|
||
currentIndex = index || 0;
|
||
currentZoom = 1;
|
||
|
||
// Origin animation
|
||
if (originEl) {
|
||
var rect = originEl.getBoundingClientRect();
|
||
lightboxEl.style.setProperty('--imgbox-origin-top', (rect.top + rect.height / 2) + 'px');
|
||
lightboxEl.style.setProperty('--imgbox-origin-left', (rect.left + rect.width / 2) + 'px');
|
||
lightboxEl.classList.add('from-origin');
|
||
} else {
|
||
lightboxEl.classList.remove('from-origin');
|
||
}
|
||
|
||
showLightboxImage(currentIndex);
|
||
buildThumbnails();
|
||
|
||
lightboxEl.classList.add('is-open');
|
||
document.body.style.overflow = 'hidden';
|
||
|
||
lightboxEl.dispatchEvent(new CustomEvent('aksrt:lightbox-open', { bubbles: true }));
|
||
}
|
||
|
||
function showLightboxImage(index) {
|
||
if (index < 0) index = currentGallery.length - 1;
|
||
if (index >= currentGallery.length) index = 0;
|
||
currentIndex = index;
|
||
setZoom(1);
|
||
|
||
var item = currentGallery[currentIndex];
|
||
lightboxImg.src = item.fullSrc || item.src;
|
||
lightboxImg.alt = item.caption || '';
|
||
lightboxCaption.textContent = item.caption || '';
|
||
lightboxCaption.style.display = item.caption ? '' : 'none';
|
||
|
||
if (currentGallery.length > 1) {
|
||
lightboxCounter.textContent = (currentIndex + 1) + ' / ' + currentGallery.length;
|
||
lightboxCounter.style.display = '';
|
||
} else {
|
||
lightboxCounter.style.display = 'none';
|
||
}
|
||
|
||
syncThumbActive();
|
||
}
|
||
|
||
function navigateLightbox(dir) {
|
||
showLightboxImage(currentIndex + dir);
|
||
}
|
||
|
||
function closeLightbox() {
|
||
if (!lightboxEl) return;
|
||
if (isAutoplay) toggleAutoplay();
|
||
lightboxEl.classList.remove('is-open', 'is-zoomed', 'from-origin');
|
||
document.body.style.overflow = '';
|
||
lightboxThumbsWrap.hidden = true;
|
||
if (document.fullscreenElement) {
|
||
(document.exitFullscreen || document.webkitExitFullscreen || document.msExitFullscreen).call(document);
|
||
}
|
||
}
|
||
|
||
// Auto-bind: expanded trigger scope + exclusion rules
|
||
function initLightbox() {
|
||
document.addEventListener('click', function (e) {
|
||
// Also support a[data-imgbox]
|
||
var anchor = e.target.closest('a[data-imgbox]');
|
||
if (anchor) {
|
||
e.preventDefault();
|
||
var href = anchor.getAttribute('href') || anchor.getAttribute('data-imgbox');
|
||
openLightbox(href, '', [{ src: href, fullSrc: href, caption: '' }], 0, anchor);
|
||
return;
|
||
}
|
||
|
||
var img = e.target.closest(TRIGGER_SEL);
|
||
if (!img) return;
|
||
if (img.width < 100 || img.height < 100) return;
|
||
if (!lightboxEnabled() || isNoLightbox(img)) return;
|
||
|
||
e.preventDefault();
|
||
|
||
var container = img.closest(CONTAINER_SEL);
|
||
if (!container) return;
|
||
|
||
var allImages = container.querySelectorAll('img');
|
||
var gallery = [];
|
||
var foundIndex = 0;
|
||
|
||
allImages.forEach(function (el) {
|
||
if (el.width < 100 || el.height < 100) return;
|
||
if (isNoLightbox(el)) return;
|
||
var full = resolveFullUrl(el);
|
||
var caption = el.alt || '';
|
||
var figcaption = el.closest('figure') ? el.closest('figure').querySelector('figcaption') : null;
|
||
if (figcaption) caption = figcaption.textContent;
|
||
gallery.push({ src: el.dataset.src || el.src, fullSrc: full, caption: caption });
|
||
if (el === img) foundIndex = gallery.length - 1;
|
||
});
|
||
|
||
if (gallery.length > 0) {
|
||
openLightbox(img.dataset.src || img.src, img.alt, gallery, foundIndex, img);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 暴露到全局
|
||
window.AksrtLightbox = {
|
||
open: openLightbox,
|
||
close: closeLightbox,
|
||
};
|
||
|
||
/* ============================================================
|
||
* 3. 滚动方向感知
|
||
* ============================================================ */
|
||
// Scroll direction is now handled by aksrt-runtime.js body scroll bus
|
||
// (body.scroll-down / body.scroll-up / body.body-scroll).
|
||
// This stub syncs the legacy aksrt-* prefixed classes for backward compat.
|
||
function initScrollDirection() {
|
||
var body = document.body;
|
||
|
||
function sync() {
|
||
body.classList.toggle('aksrt-body-scroll', body.classList.contains('body-scroll'));
|
||
body.classList.toggle('aksrt-scroll-down', body.classList.contains('scroll-down'));
|
||
body.classList.toggle('aksrt-scroll-up', body.classList.contains('scroll-up'));
|
||
|
||
body.classList.add('aksrt-scrolling');
|
||
clearTimeout(body._aksrtScrollTimer);
|
||
body._aksrtScrollTimer = setTimeout(function () {
|
||
body.classList.remove('aksrt-scrolling');
|
||
}, 300);
|
||
}
|
||
|
||
function onScroll() {
|
||
requestAnimationFrame(sync);
|
||
}
|
||
|
||
window.addEventListener('scroll', onScroll, { passive: true });
|
||
}
|
||
|
||
/* ============================================================
|
||
* 4. 导航溢出自动折叠
|
||
* 菜单项超出容器宽度时折叠进「更多」下拉
|
||
* ============================================================ */
|
||
function initNavOverflow() {
|
||
var nav = document.querySelector('.site-nav .nav-menu, .site-nav .primary-nav, .header-nav__menu');
|
||
if (!nav) return;
|
||
|
||
// 创建「更多」按钮
|
||
var moreLi = document.createElement('li');
|
||
moreLi.className = 'nav-item aksrt-nav-more';
|
||
moreLi.style.display = 'none';
|
||
moreLi.innerHTML =
|
||
'<button type="button" class="aksrt-nav-more__btn" aria-haspopup="true" aria-expanded="false">更多 <i class="fas fa-caret-down"></i></button>' +
|
||
'<ul class="aksrt-nav-more__dropdown"></ul>';
|
||
nav.appendChild(moreLi);
|
||
|
||
var moreBtn = moreLi.querySelector('.aksrt-nav-more__btn');
|
||
var dropdown = moreLi.querySelector('.aksrt-nav-more__dropdown');
|
||
|
||
moreBtn.addEventListener('click', function (e) {
|
||
e.stopPropagation();
|
||
var open = dropdown.classList.toggle('is-open');
|
||
moreBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||
});
|
||
|
||
document.addEventListener('click', function () {
|
||
dropdown.classList.remove('is-open');
|
||
moreBtn.setAttribute('aria-expanded', 'false');
|
||
});
|
||
|
||
function checkOverflow() {
|
||
var items = Array.from(nav.children).filter(function (el) {
|
||
return !el.classList.contains('aksrt-nav-more');
|
||
});
|
||
|
||
// 重置:把所有项移回原位
|
||
while (dropdown.firstChild) {
|
||
var li = dropdown.firstChild;
|
||
nav.insertBefore(li, moreLi);
|
||
}
|
||
moreLi.style.display = 'none';
|
||
|
||
var navWidth = nav.clientWidth;
|
||
var moreWidth = 80; // 预留「更多」按钮宽度
|
||
var usedWidth = 0;
|
||
var overflowItems = [];
|
||
|
||
items.forEach(function (item) {
|
||
usedWidth += item.offsetWidth;
|
||
if (usedWidth + moreWidth > navWidth) {
|
||
overflowItems.push(item);
|
||
}
|
||
});
|
||
|
||
if (overflowItems.length > 0) {
|
||
moreLi.style.display = '';
|
||
overflowItems.forEach(function (item) {
|
||
dropdown.appendChild(item);
|
||
});
|
||
}
|
||
}
|
||
|
||
// ResizeObserver 监听(避免 resize 抖动)
|
||
if ('ResizeObserver' in window) {
|
||
var timer = null;
|
||
var ro = new ResizeObserver(function () {
|
||
if (timer) clearTimeout(timer);
|
||
timer = setTimeout(checkOverflow, 100);
|
||
});
|
||
ro.observe(nav);
|
||
} else {
|
||
window.addEventListener('resize', checkOverflow, { passive: true });
|
||
}
|
||
|
||
// 初始检测
|
||
checkOverflow();
|
||
}
|
||
|
||
/* ============================================================
|
||
* 初始化入口
|
||
* ============================================================ */
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
initLightbox();
|
||
initScrollDirection();
|
||
initNavOverflow();
|
||
});
|
||
|
||
})();
|