582 lines
24 KiB
JavaScript
582 lines
24 KiB
JavaScript
// js/ui/immersive_layout_logic.js
|
||
(function ImmersiveLayoutLogic(global) {
|
||
let toggleBtn, immersiveContainer;
|
||
let mainPageContainer, tocPopupElement, chatbotModalElement, dockElement;
|
||
let immersiveTocArea, immersiveMainArea, immersiveChatbotArea, immersiveDockPlaceholderElement;
|
||
let tocVsDockResizeHandle;
|
||
let isTocDockResizing = false; // Flag to indicate dragging state
|
||
let initialTocDockMouseY, initialTocHeight, initialDockHeight;
|
||
|
||
// Original parent and next sibling of the elements to be moved
|
||
let originalMainContainerParent = null;
|
||
let originalMainContainerNextSibling = null;
|
||
let originalTocPopupParent = null;
|
||
let originalTocPopupNextSibling = null;
|
||
let originalChatbotModalParent = null;
|
||
let originalChatbotModalNextSibling = null;
|
||
let originalDockElementParent = null;
|
||
let originalDockElementNextSibling = null;
|
||
|
||
let isImmersiveActive = false;
|
||
let isSimpleImmersiveActive = false; // 新增:简单沉浸模式状态
|
||
const LS_IMMERSIVE_KEY = 'immersiveLayoutActive';
|
||
const LS_SIMPLE_IMMERSIVE_KEY = 'simpleImmersiveLayoutActive'; // 新增:简单沉浸模式存储键
|
||
const LS_PANEL_SIZES_KEY = 'immersivePanelSizes';
|
||
|
||
function initializeDomElements() {
|
||
toggleBtn = document.getElementById('toggle-immersive-btn');
|
||
immersiveContainer = document.getElementById('immersive-layout-container');
|
||
|
||
mainPageContainer = document.querySelector('.container');
|
||
tocPopupElement = document.getElementById('toc-popup');
|
||
chatbotModalElement = document.getElementById('chatbot-modal');
|
||
dockElement = document.getElementById('bottom-left-dock');
|
||
|
||
immersiveTocArea = document.getElementById('immersive-toc-area');
|
||
immersiveMainArea = document.getElementById('immersive-main-content-area');
|
||
immersiveChatbotArea = document.getElementById('immersive-chatbot-area');
|
||
|
||
// Create the dock placeholder dynamically
|
||
immersiveDockPlaceholderElement = document.createElement('div');
|
||
immersiveDockPlaceholderElement.id = 'toc-dock-placeholder';
|
||
// Basic styles can be applied here if not fully covered by CSS, or rely on CSS.
|
||
// For now, CSS will handle styling based on the ID.
|
||
|
||
return toggleBtn && immersiveContainer && mainPageContainer && tocPopupElement && immersiveTocArea && immersiveMainArea && immersiveChatbotArea && dockElement /* && immersiveDockPlaceholderElement (element itself exists, not a check if found in DOM here) */;
|
||
}
|
||
|
||
function reQueryDynamicElements() {
|
||
if (!chatbotModalElement) {
|
||
chatbotModalElement = document.getElementById('chatbot-modal');
|
||
}
|
||
if (!mainPageContainer) mainPageContainer = document.querySelector('.container');
|
||
if (!tocPopupElement) tocPopupElement = document.getElementById('toc-popup');
|
||
if (!dockElement) dockElement = document.getElementById('bottom-left-dock');
|
||
}
|
||
|
||
function storeOriginalPositions() {
|
||
if (mainPageContainer) {
|
||
originalMainContainerParent = mainPageContainer.parentNode;
|
||
originalMainContainerNextSibling = mainPageContainer.nextSibling;
|
||
}
|
||
if (tocPopupElement) {
|
||
originalTocPopupParent = tocPopupElement.parentNode;
|
||
originalTocPopupNextSibling = tocPopupElement.nextSibling;
|
||
}
|
||
if (chatbotModalElement) {
|
||
originalChatbotModalParent = chatbotModalElement.parentNode;
|
||
originalChatbotModalNextSibling = chatbotModalElement.nextSibling;
|
||
} else {
|
||
console.warn('storeOriginalPositions: chatbotModalElement not found.');
|
||
}
|
||
if (dockElement) {
|
||
originalDockElementParent = dockElement.parentNode;
|
||
originalDockElementNextSibling = dockElement.nextSibling;
|
||
} else {
|
||
console.warn('storeOriginalPositions: dockElement not found.');
|
||
}
|
||
}
|
||
|
||
function savePanelSizes() {
|
||
if (!isImmersiveActive || !immersiveContainer || immersiveContainer.style.display === 'none') return;
|
||
if (!immersiveTocArea || !immersiveMainArea || !immersiveChatbotArea) return;
|
||
|
||
const tocWidth = immersiveTocArea.style.width;
|
||
const mainWidth = immersiveMainArea.style.width;
|
||
const chatbotWidth = immersiveChatbotArea.style.width;
|
||
localStorage.setItem(LS_PANEL_SIZES_KEY, JSON.stringify({ toc: tocWidth, main: mainWidth, chatbot: chatbotWidth }));
|
||
}
|
||
|
||
function loadPanelSizes() {
|
||
if (!immersiveTocArea || !immersiveMainArea || !immersiveChatbotArea) return;
|
||
|
||
const savedSizes = localStorage.getItem(LS_PANEL_SIZES_KEY);
|
||
if (savedSizes) {
|
||
try {
|
||
const sizes = JSON.parse(savedSizes);
|
||
if (sizes.toc) immersiveTocArea.style.width = sizes.toc;
|
||
if (sizes.chatbot) immersiveChatbotArea.style.width = sizes.chatbot;
|
||
} catch (e) {
|
||
console.error('Error loading panel sizes:', e);
|
||
immersiveTocArea.style.width = '20%';
|
||
immersiveMainArea.style.flex = '1';
|
||
immersiveMainArea.style.width = '';
|
||
immersiveChatbotArea.style.width = '25%';
|
||
}
|
||
} else {
|
||
immersiveTocArea.style.width = '20%';
|
||
immersiveMainArea.style.flex = '1';
|
||
immersiveMainArea.style.width = '';
|
||
immersiveChatbotArea.style.width = '25%';
|
||
}
|
||
}
|
||
|
||
function initializeTocDockResizer() {
|
||
if (!tocVsDockResizeHandle || !tocPopupElement || !immersiveDockPlaceholderElement || !immersiveTocArea) {
|
||
console.warn("TOC vs Dock resizer: Missing one or more elements.");
|
||
return;
|
||
}
|
||
|
||
// Ensure event listeners are not duplicated if called multiple times
|
||
tocVsDockResizeHandle.removeEventListener('mousedown', handleTocDockDragStart);
|
||
tocVsDockResizeHandle.addEventListener('mousedown', handleTocDockDragStart);
|
||
}
|
||
|
||
function handleTocDockDragStart(event) {
|
||
event.preventDefault();
|
||
isTocDockResizing = true;
|
||
|
||
initialTocDockMouseY = event.clientY;
|
||
initialTocHeight = tocPopupElement.offsetHeight;
|
||
initialDockHeight = immersiveDockPlaceholderElement.offsetHeight;
|
||
|
||
// Add class to body for global cursor/selection styles
|
||
document.body.classList.add('toc-dock-resizing');
|
||
|
||
// Add temporary flex-grow overrides if needed, or rely on flex-basis
|
||
// tocPopupElement.style.flexGrow = '0';
|
||
// immersiveDockPlaceholderElement.style.flexGrow = '0';
|
||
|
||
|
||
document.addEventListener('mousemove', handleTocDockDragMove);
|
||
document.addEventListener('mouseup', handleTocDockDragEnd);
|
||
}
|
||
|
||
function handleTocDockDragMove(event) {
|
||
if (!isTocDockResizing) return;
|
||
event.preventDefault();
|
||
|
||
const deltaY = event.clientY - initialTocDockMouseY;
|
||
let newTocHeight = initialTocHeight + deltaY;
|
||
let newDockHeight = initialDockHeight - deltaY;
|
||
|
||
const minPanelHeight = 40; // Minimum height for TOC and Dock panels
|
||
|
||
// Constrain TOC height
|
||
if (newTocHeight < minPanelHeight) {
|
||
newTocHeight = minPanelHeight;
|
||
// Recalculate dock height based on constrained TOC
|
||
newDockHeight = initialTocHeight + initialDockHeight - newTocHeight;
|
||
}
|
||
|
||
// Constrain Dock height
|
||
if (newDockHeight < minPanelHeight) {
|
||
newDockHeight = minPanelHeight;
|
||
// Recalculate TOC height based on constrained Dock
|
||
newTocHeight = initialTocHeight + initialDockHeight - newDockHeight;
|
||
}
|
||
|
||
// Ensure total height of tocArea children doesn't exceed tocArea height if it's fixed
|
||
// For flexbox, adjusting flex-basis is usually better.
|
||
// The sum of newTocHeight and newDockHeight should ideally be initialTocHeight + initialDockHeight.
|
||
// The logic above ensures this if one hits minPanelHeight.
|
||
|
||
// Apply new heights using flex-basis for better control in a flex container
|
||
tocPopupElement.style.flexBasis = newTocHeight + 'px';
|
||
immersiveDockPlaceholderElement.style.flexBasis = newDockHeight + 'px';
|
||
|
||
// If not using flex-basis, and want to force height and disable grow/shrink during drag:
|
||
// tocPopupElement.style.height = newTocHeight + 'px';
|
||
// immersiveDockPlaceholderElement.style.height = newDockHeight + 'px';
|
||
// tocPopupElement.style.flexGrow = '0';
|
||
// immersiveDockPlaceholderElement.style.flexGrow = '0';
|
||
|
||
}
|
||
|
||
function handleTocDockDragEnd() {
|
||
if (!isTocDockResizing) return;
|
||
isTocDockResizing = false;
|
||
|
||
document.body.classList.remove('toc-dock-resizing');
|
||
document.removeEventListener('mousemove', handleTocDockDragMove);
|
||
document.removeEventListener('mouseup', handleTocDockDragEnd);
|
||
|
||
// Restore original flex-grow properties if they were changed during drag
|
||
// tocPopupElement.style.flexGrow = ''; // Or to its original value e.g., '10'
|
||
// immersiveDockPlaceholderElement.style.flexGrow = ''; // Or to its original value e.g., '1'
|
||
// However, since we are using flex-basis, the original flex-grow values from CSS should still apply
|
||
// once flex-basis is set, unless grow/shrink are explicitly set to 0.
|
||
// The CSS has flex-grow: 10 for toc and flex-grow: 1 for dock placeholder.
|
||
// Setting flex-basis should work fine with these grow factors if space allows.
|
||
|
||
// Optional: Save the new heights/proportions to localStorage
|
||
// const tocAreaHeight = immersiveTocArea.offsetHeight;
|
||
// if (tocAreaHeight > 0) {
|
||
// const tocRatio = tocPopupElement.offsetHeight / tocAreaHeight;
|
||
// localStorage.setItem('immersiveTocDockRatio', tocRatio.toFixed(4));
|
||
// }
|
||
}
|
||
|
||
function destroyTocDockResizer() {
|
||
if (tocVsDockResizeHandle) {
|
||
tocVsDockResizeHandle.removeEventListener('mousedown', handleTocDockDragStart);
|
||
}
|
||
// Clean up global listeners if somehow left hanging (should be removed by handleTocDockDragEnd)
|
||
document.removeEventListener('mousemove', handleTocDockDragMove);
|
||
document.removeEventListener('mouseup', handleTocDockDragEnd);
|
||
document.body.classList.remove('toc-dock-resizing');
|
||
isTocDockResizing = false; // Reset flag
|
||
}
|
||
|
||
function enterImmersiveMode(options = {}) {
|
||
const { silent = false } = options;
|
||
|
||
// 检查是否为移动端设备
|
||
if (window.innerWidth <= 700) {
|
||
console.warn('拒绝在移动端(≤700px)进入沉浸式布局');
|
||
// 移动端:显示普通布局
|
||
document.documentElement.classList.remove('immersive-pending');
|
||
document.documentElement.classList.add('immersive-ready');
|
||
document.body.classList.remove('immersive-pending');
|
||
document.body.classList.add('immersive-ready');
|
||
return true; // 移动端算作成功
|
||
}
|
||
|
||
reQueryDynamicElements();
|
||
|
||
let missingElements = [];
|
||
if (!immersiveContainer) missingElements.push('immersiveContainer');
|
||
if (!mainPageContainer) missingElements.push('mainPageContainer');
|
||
if (!tocPopupElement) missingElements.push('tocPopupElement');
|
||
if (!chatbotModalElement) missingElements.push('chatbotModalElement');
|
||
if (!dockElement) missingElements.push('dockElement');
|
||
if (!immersiveTocArea) missingElements.push('immersiveTocArea');
|
||
if (!immersiveMainArea) missingElements.push('immersiveMainArea');
|
||
if (!immersiveChatbotArea) missingElements.push('immersiveChatbotArea');
|
||
if (!immersiveDockPlaceholderElement) missingElements.push('immersiveDockPlaceholderElement (logic error if this happens)');
|
||
|
||
console.log('[enterImmersiveMode] 元素检查:', {
|
||
immersiveContainer: !!immersiveContainer,
|
||
mainPageContainer: !!mainPageContainer,
|
||
tocPopupElement: !!tocPopupElement,
|
||
chatbotModalElement: !!chatbotModalElement,
|
||
dockElement: !!dockElement,
|
||
immersiveTocArea: !!immersiveTocArea,
|
||
immersiveMainArea: !!immersiveMainArea,
|
||
immersiveChatbotArea: !!immersiveChatbotArea
|
||
});
|
||
|
||
// 【严格检查】如果元素缺失,返回 false 表示失败,不显示页面
|
||
// 调用者应该重试直到成功
|
||
if (missingElements.length > 0) {
|
||
console.error('[enterImmersiveMode] 严重错误:沉浸模式元素缺失:', missingElements.join(', '));
|
||
console.error('[enterImmersiveMode] 拒绝显示普通布局,等待重试...');
|
||
return false; // 返回失败,不显示页面
|
||
}
|
||
|
||
isImmersiveActive = true;
|
||
storeOriginalPositions();
|
||
|
||
// 静默模式:跳过动画,直接设置状态
|
||
if (silent) {
|
||
document.body.classList.add('immersive-active', 'no-scroll');
|
||
immersiveContainer.style.display = 'flex';
|
||
immersiveContainer.style.opacity = '1';
|
||
immersiveContainer.style.transform = 'scale(1)';
|
||
} else {
|
||
// 添加进入动画类
|
||
document.body.classList.add('immersive-entering');
|
||
immersiveContainer.style.opacity = '0';
|
||
immersiveContainer.style.transform = 'scale(0.95)';
|
||
immersiveContainer.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
|
||
}
|
||
|
||
// Append TOC content first
|
||
if (tocPopupElement && immersiveTocArea) {
|
||
immersiveTocArea.appendChild(tocPopupElement);
|
||
}
|
||
|
||
// Create and insert the resize handle between TOC and Dock Placeholder
|
||
if (immersiveTocArea) {
|
||
if (!tocVsDockResizeHandle) { // Create if it doesn't exist
|
||
tocVsDockResizeHandle = document.createElement('div');
|
||
tocVsDockResizeHandle.id = 'toc-vs-dock-resize-handle';
|
||
}
|
||
if (tocPopupElement && tocPopupElement.parentNode === immersiveTocArea) {
|
||
immersiveTocArea.insertBefore(tocVsDockResizeHandle, tocPopupElement.nextSibling);
|
||
} else {
|
||
immersiveTocArea.appendChild(tocVsDockResizeHandle);
|
||
}
|
||
}
|
||
|
||
// Then append the dock placeholder to TOC area
|
||
if (immersiveDockPlaceholderElement && immersiveTocArea) {
|
||
if (tocVsDockResizeHandle && tocVsDockResizeHandle.parentNode === immersiveTocArea) {
|
||
immersiveTocArea.insertBefore(immersiveDockPlaceholderElement, tocVsDockResizeHandle.nextSibling);
|
||
} else {
|
||
immersiveTocArea.appendChild(immersiveDockPlaceholderElement);
|
||
}
|
||
}
|
||
|
||
// Move other elements
|
||
if (mainPageContainer && immersiveMainArea) {
|
||
immersiveMainArea.appendChild(mainPageContainer);
|
||
}
|
||
if (chatbotModalElement && immersiveChatbotArea) {
|
||
immersiveChatbotArea.appendChild(chatbotModalElement);
|
||
}
|
||
|
||
// Move the actual dock into its placeholder
|
||
if (dockElement && immersiveDockPlaceholderElement) {
|
||
immersiveDockPlaceholderElement.appendChild(dockElement);
|
||
|
||
// Force Dock to be expanded in immersive mode
|
||
if (dockElement.classList.contains('dock-collapsed')) {
|
||
dockElement.classList.remove('dock-collapsed');
|
||
const dockToggleBtn = document.getElementById('dock-toggle-btn');
|
||
if (dockToggleBtn) {
|
||
dockToggleBtn.innerHTML = '<i class="fa fa-chevron-down"></i>';
|
||
dockToggleBtn.title = '折叠';
|
||
}
|
||
if (typeof window !== 'undefined' && window.docIdForLocalStorage) {
|
||
localStorage.setItem(`dockCollapsed_${window.docIdForLocalStorage}`, 'false');
|
||
}
|
||
}
|
||
}
|
||
|
||
// 静默模式下已经设置了 display 和 opacity,跳过动画
|
||
if (!silent) {
|
||
document.body.classList.add('immersive-active', 'no-scroll');
|
||
immersiveContainer.style.display = 'flex';
|
||
|
||
// 简单的强制重新计算,修复初始化时的布局问题
|
||
setTimeout(() => {
|
||
if (immersiveContainer) {
|
||
immersiveContainer.offsetHeight; // 触发重新布局
|
||
}
|
||
}, 0);
|
||
|
||
// 动画进入效果
|
||
requestAnimationFrame(() => {
|
||
immersiveContainer.style.opacity = '1';
|
||
immersiveContainer.style.transform = 'scale(1)';
|
||
|
||
setTimeout(() => {
|
||
document.body.classList.remove('immersive-entering');
|
||
immersiveContainer.style.transition = '';
|
||
}, 400);
|
||
});
|
||
}
|
||
|
||
// 显示页面(移除 pending 状态)
|
||
document.documentElement.classList.remove('immersive-pending');
|
||
document.documentElement.classList.add('immersive-ready');
|
||
document.body.classList.remove('immersive-pending');
|
||
document.body.classList.add('immersive-ready');
|
||
|
||
if (toggleBtn) {
|
||
toggleBtn.innerHTML = '<i class="fas fa-compress-alt"></i>';
|
||
toggleBtn.classList.add('immersive-exit-btn-active');
|
||
toggleBtn.title = '退出沉浸模式';
|
||
}
|
||
|
||
// 其他初始化逻辑保持不变...
|
||
if (typeof window.refreshTocList === 'function') {
|
||
window.refreshTocList();
|
||
}
|
||
if (window.ChatbotUI && typeof window.ChatbotUI.updateChatbotUI === 'function') {
|
||
window.isChatbotOpen = true;
|
||
window.isChatbotFullscreen = false;
|
||
window.forceChatbotWidthReset = true;
|
||
window.ChatbotUI.updateChatbotUI();
|
||
}
|
||
if (window.DockLogic && typeof window.DockLogic.updateStats === 'function' && window.data && window.currentVisibleTabId) {
|
||
dockElement.style.display = '';
|
||
window.DockLogic.updateStats(window.data, window.currentVisibleTabId);
|
||
}
|
||
|
||
setTimeout(() => {
|
||
if (window.DockLogic) {
|
||
if (typeof window.DockLogic.unbindScrollForCurrentScrollable === 'function') {
|
||
console.log("[ImmersiveLayout] 进入沉浸模式前,先解绑旧的滚动事件");
|
||
window.DockLogic.unbindScrollForCurrentScrollable();
|
||
}
|
||
if (typeof window.DockLogic.forceUpdateReadingProgress === 'function') {
|
||
console.log("[ImmersiveLayout] 进入沉浸模式后,延迟调用 forceUpdateReadingProgress");
|
||
window.DockLogic.forceUpdateReadingProgress();
|
||
}
|
||
}
|
||
|
||
// 为滚动容器添加标记 class,供 JS 查询使用
|
||
if (immersiveMainArea) {
|
||
const container = immersiveMainArea.querySelector('.container');
|
||
if (container) {
|
||
const tabContent = container.querySelector('.tab-content');
|
||
if (tabContent) {
|
||
// 添加 .js-scroll-container 标记,供 DockLogic 等模块查询
|
||
// CSS 通过 body.immersive-active 选择器自动控制 overflow
|
||
tabContent.classList.add('js-scroll-container');
|
||
console.log("[ImmersiveLayout] 已为 tab-content 添加 js-scroll-container 标记");
|
||
}
|
||
}
|
||
}
|
||
}, 300);
|
||
|
||
// Force TOC to be expanded in immersive mode
|
||
if (tocPopupElement && !tocPopupElement.classList.contains('toc-expanded')) {
|
||
const tocExpandBtn = document.getElementById('toc-expand-btn');
|
||
if (tocExpandBtn) {
|
||
tocPopupElement.classList.add('toc-expanded');
|
||
const icon = tocExpandBtn.querySelector('i');
|
||
if (icon) {
|
||
icon.classList.remove('fa-angles-right');
|
||
icon.classList.add('fa-angles-left');
|
||
}
|
||
tocExpandBtn.title = '收起目录';
|
||
}
|
||
}
|
||
|
||
loadPanelSizes();
|
||
initializeTocDockResizer();
|
||
localStorage.setItem(LS_IMMERSIVE_KEY, 'true');
|
||
document.dispatchEvent(new CustomEvent('immersiveModeEntered'));
|
||
|
||
return true; // 成功进入沉浸模式
|
||
}
|
||
// 禁用退出沉浸模式功能 - 页面始终保持在沉浸式布局
|
||
function exitImmersiveMode() {
|
||
// 已禁用:页面始终保持在沉浸式布局
|
||
console.log('[ImmersiveLayout] 退出沉浸模式功能已禁用');
|
||
}
|
||
|
||
function initResizeHandles() {
|
||
const handles = document.querySelectorAll('.immersive-resize-handle');
|
||
let activeHandle = null;
|
||
let startX, startWidthPrev, startWidthNext;
|
||
|
||
handles.forEach(handle => {
|
||
handle.addEventListener('mousedown', function(e) {
|
||
activeHandle = this;
|
||
startX = e.clientX;
|
||
const prevPanelId = activeHandle.dataset.targetPrev;
|
||
const nextPanelId = activeHandle.dataset.targetNext;
|
||
const prevPanel = document.getElementById(prevPanelId);
|
||
const nextPanel = document.getElementById(nextPanelId);
|
||
|
||
if (!prevPanel || !nextPanel) {
|
||
console.warn(`Resize panels not found: ${prevPanelId} or ${nextPanelId}`);
|
||
activeHandle = null;
|
||
return;
|
||
}
|
||
|
||
startWidthPrev = prevPanel.offsetWidth;
|
||
startWidthNext = nextPanel.offsetWidth;
|
||
|
||
document.body.classList.add('immersive-dragging');
|
||
document.body.style.userSelect = 'none';
|
||
document.body.style.cursor = 'col-resize';
|
||
|
||
e.preventDefault();
|
||
});
|
||
});
|
||
|
||
document.addEventListener('mousemove', function(e) {
|
||
if (!activeHandle) return;
|
||
|
||
const dx = e.clientX - startX;
|
||
const prevPanel = document.getElementById(activeHandle.dataset.targetPrev);
|
||
const nextPanel = document.getElementById(activeHandle.dataset.targetNext);
|
||
|
||
if (!prevPanel || !nextPanel) return;
|
||
|
||
const newWidthPrev = startWidthPrev + dx;
|
||
const newWidthNext = startWidthNext - dx;
|
||
const minPanelWidth = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--immersive-panel-min-width')) || 80;
|
||
|
||
if (newWidthPrev >= minPanelWidth && newWidthNext >= minPanelWidth) {
|
||
prevPanel.style.width = newWidthPrev + 'px';
|
||
nextPanel.style.width = newWidthNext + 'px';
|
||
|
||
// 平滑的过渡动画
|
||
prevPanel.style.transition = 'none';
|
||
nextPanel.style.transition = 'none';
|
||
}
|
||
});
|
||
|
||
document.addEventListener('mouseup', function() {
|
||
if (activeHandle) {
|
||
savePanelSizes();
|
||
|
||
// 恢复样式
|
||
document.body.classList.remove('immersive-dragging');
|
||
document.body.style.userSelect = '';
|
||
document.body.style.cursor = '';
|
||
|
||
// 恢复过渡动画
|
||
const prevPanel = document.getElementById(activeHandle.dataset.targetPrev);
|
||
const nextPanel = document.getElementById(activeHandle.dataset.targetNext);
|
||
if (prevPanel) prevPanel.style.transition = '';
|
||
if (nextPanel) nextPanel.style.transition = '';
|
||
|
||
activeHandle = null;
|
||
}
|
||
});
|
||
}
|
||
|
||
function mainInit() {
|
||
if (!initializeDomElements()) {
|
||
console.warn('[ImmersiveLayout] 核心静态元素未找到,200ms 后重试...');
|
||
setTimeout(mainInit, 200);
|
||
return;
|
||
}
|
||
|
||
reQueryDynamicElements();
|
||
|
||
// 按钮已隐藏,退出功能已禁用,页面始终处于沉浸模式
|
||
// 不再需要按钮事件监听器
|
||
|
||
initResizeHandles();
|
||
|
||
// 禁用:窗口大小变化时不再自动退出沉浸模式
|
||
// function handleWindowResize() {
|
||
// if (window.innerWidth <= 700 && isImmersiveActive) {
|
||
// console.log('检测到屏幕缩小到移动端尺寸,自动退出沉浸式布局');
|
||
// exitImmersiveMode();
|
||
// }
|
||
// }
|
||
// window.addEventListener('resize', handleWindowResize);
|
||
|
||
// 【严格沉浸模式】必须成功进入沉浸模式才显示页面
|
||
console.log('[ImmersiveLayout] 强制进入沉浸模式');
|
||
|
||
// 检查是否为移动端,如果是则显示普通布局
|
||
if (window.innerWidth <= 700) {
|
||
console.log('[ImmersiveLayout] 检测到移动端设备,显示普通布局');
|
||
document.documentElement.classList.remove('immersive-pending');
|
||
document.documentElement.classList.add('immersive-ready');
|
||
document.body.classList.remove('immersive-pending');
|
||
document.body.classList.add('immersive-ready');
|
||
return;
|
||
}
|
||
|
||
// 尝试进入沉浸模式(静默模式,无动画)
|
||
const success = enterImmersiveMode({ silent: true });
|
||
|
||
if (success) {
|
||
console.log('[ImmersiveLayout] 成功进入沉浸模式');
|
||
} else {
|
||
// 失败时持续重试,不显示页面
|
||
console.error('[ImmersiveLayout] 进入沉浸模式失败,300ms 后重试...');
|
||
setTimeout(mainInit, 300);
|
||
return;
|
||
}
|
||
|
||
console.log('Immersive layout logic initialized.');
|
||
}
|
||
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', mainInit);
|
||
} else {
|
||
mainInit();
|
||
}
|
||
|
||
global.ImmersiveLayout = {
|
||
isActive: () => isImmersiveActive,
|
||
isSimpleActive: () => isSimpleImmersiveActive, // 新增:简单沉浸模式状态查询
|
||
enter: enterImmersiveMode,
|
||
exit: exitImmersiveMode
|
||
};
|
||
|
||
})(window);
|
||
|