246 lines
9.0 KiB
JavaScript
246 lines
9.0 KiB
JavaScript
|
|
// ========================================
|
|||
|
|
// 顶栏合并左右间距功能模块
|
|||
|
|
// ========================================
|
|||
|
|
|
|||
|
|
import { debounce, throttle } from './utils.js';
|
|||
|
|
|
|||
|
|
// 存储观察器实例
|
|||
|
|
let rightPanelObserver = null;
|
|||
|
|
let leftPanelObserver = null;
|
|||
|
|
let dockVerticalObserver = null;
|
|||
|
|
let layoutCenterObserver = null;
|
|||
|
|
|
|||
|
|
// 存储更新函数
|
|||
|
|
let updateRightMargins = null;
|
|||
|
|
let updateLeftMargins = null;
|
|||
|
|
|
|||
|
|
// 检测是否为 macOS 平台
|
|||
|
|
const isMacOS = () => {
|
|||
|
|
return navigator.userAgent.includes('Macintosh') || navigator.userAgent.includes('Mac OS X');
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 初始化顶栏合并左右间距功能
|
|||
|
|
* @param {string} direction - 方向,"right" 或 "left"
|
|||
|
|
*/
|
|||
|
|
export const initTabBarsMarginUnified = (direction = "right") => {
|
|||
|
|
const isRight = direction === "right";
|
|||
|
|
|
|||
|
|
// 更新边距的函数
|
|||
|
|
const updateMargins = () => {
|
|||
|
|
const isTopbarMerged = document.documentElement.getAttribute('savor-tabbar') === 'merge';
|
|||
|
|
const tabBarSelector = isRight
|
|||
|
|
? ".layout__center .layout-tab-bar--readonly"
|
|||
|
|
: ".layout__center .layout-tab-bar:not(.layout-tab-bar--readonly)";
|
|||
|
|
const allTabBars = document.querySelectorAll(tabBarSelector);
|
|||
|
|
|
|||
|
|
if (!isTopbarMerged) {
|
|||
|
|
allTabBars.forEach(tabBar => {
|
|||
|
|
tabBar.style[isRight ? "marginRight" : "marginLeft"] = "0px";
|
|||
|
|
});
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取窗口和drag元素的位置信息
|
|||
|
|
const drag = document.getElementById("drag");
|
|||
|
|
let marginValue = "0px";
|
|||
|
|
|
|||
|
|
if (drag) {
|
|||
|
|
if (isRight) {
|
|||
|
|
// 计算 #drag 到窗口右边界的距离
|
|||
|
|
const dragRect = drag.getBoundingClientRect();
|
|||
|
|
const windowWidth = window.innerWidth;
|
|||
|
|
let distanceToWindowRight = windowWidth - dragRect.right;
|
|||
|
|
|
|||
|
|
// 减去右侧dock的宽度
|
|||
|
|
const rightDock = document.querySelector(".layout__dockr");
|
|||
|
|
const rightDockWidth = rightDock?.classList.contains("layout--float")
|
|||
|
|
? rightDock.querySelector(".dock")?.offsetWidth ?? 0
|
|||
|
|
: rightDock?.offsetWidth ?? 0;
|
|||
|
|
const rightDockSelector = "#dockRight";
|
|||
|
|
const rightDockRealWidth = document.querySelector(rightDockSelector)?.offsetWidth ?? 0;
|
|||
|
|
|
|||
|
|
distanceToWindowRight -= (rightDockWidth + rightDockRealWidth);
|
|||
|
|
|
|||
|
|
// 如果结果是负数,直接为0
|
|||
|
|
distanceToWindowRight = Math.max(0, distanceToWindowRight);
|
|||
|
|
|
|||
|
|
marginValue = `${distanceToWindowRight}px`;
|
|||
|
|
} else {
|
|||
|
|
// 计算 #drag 到窗口左边界的距离
|
|||
|
|
const dragRect = drag.getBoundingClientRect();
|
|||
|
|
let distanceToWindowLeft = dragRect.left;
|
|||
|
|
|
|||
|
|
// 减去左侧dock的宽度
|
|||
|
|
const leftDock = document.querySelector(".layout__dockl");
|
|||
|
|
const leftDockWidth = leftDock?.classList.contains("layout--float")
|
|||
|
|
? leftDock.querySelector(".dock")?.offsetWidth ?? 0
|
|||
|
|
: leftDock?.offsetWidth ?? 0;
|
|||
|
|
const leftDockSelector = "#dockLeft";
|
|||
|
|
const leftDockRealWidth = document.querySelector(leftDockSelector)?.offsetWidth ?? 0;
|
|||
|
|
|
|||
|
|
distanceToWindowLeft -= (leftDockWidth + leftDockRealWidth);
|
|||
|
|
|
|||
|
|
// 如果结果是负数,直接为0
|
|||
|
|
distanceToWindowLeft = Math.max(0, distanceToWindowLeft);
|
|||
|
|
|
|||
|
|
marginValue = `${distanceToWindowLeft}px`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 应用 margin
|
|||
|
|
if (isRight) {
|
|||
|
|
allTabBars.forEach(tabBar => tabBar.style.marginRight = "0px");
|
|||
|
|
const resizers = document.querySelectorAll(".layout__center .layout__resize:not(.layout__resize--lr)");
|
|||
|
|
if (resizers.length === 0) {
|
|||
|
|
const lastTabBar = allTabBars[allTabBars.length - 1];
|
|||
|
|
if (lastTabBar && (lastTabBar.closest(".layout__dockr") || lastTabBar.closest(".layout__center"))) {
|
|||
|
|
lastTabBar.style.marginRight = marginValue;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
resizers.forEach(resizer => {
|
|||
|
|
let prevElement = resizer.previousElementSibling;
|
|||
|
|
if (!prevElement) return;
|
|||
|
|
const prevTabBars = prevElement.querySelectorAll(".layout-tab-bar--readonly");
|
|||
|
|
if (prevTabBars.length > 0) {
|
|||
|
|
const lastTabBar = prevTabBars[prevTabBars.length - 1];
|
|||
|
|
if (lastTabBar.closest(".layout__dockr") || lastTabBar.closest(".layout__center")) {
|
|||
|
|
lastTabBar.style.marginRight = marginValue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
const firstTabBar = allTabBars[0];
|
|||
|
|
if (firstTabBar) {
|
|||
|
|
firstTabBar.style.marginLeft = marginValue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 为右/左侧分别存储更新函数
|
|||
|
|
if (isRight) {
|
|||
|
|
updateRightMargins = updateMargins;
|
|||
|
|
window.updateTabBarsMargin = updateMargins;
|
|||
|
|
} else {
|
|||
|
|
updateLeftMargins = updateMargins;
|
|||
|
|
window.updateTabBarsMarginLeft = updateMargins;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// observer 只初始化一次
|
|||
|
|
const dockSelector = isRight ? ".layout__dockr" : ".layout__dockl";
|
|||
|
|
const dockVerticalSelector = ".dock--vertical";
|
|||
|
|
|
|||
|
|
// 创建观察器
|
|||
|
|
const panelObserver = new ResizeObserver(updateMargins);
|
|||
|
|
const dockVerticalObserverInstance = new MutationObserver(updateMargins);
|
|||
|
|
|
|||
|
|
function observeDock() {
|
|||
|
|
const dock = document.querySelector(dockSelector);
|
|||
|
|
if (dock) panelObserver.observe(dock);
|
|||
|
|
const dockVertical = document.querySelector(dockVerticalSelector);
|
|||
|
|
if (dockVertical) {
|
|||
|
|
dockVerticalObserverInstance.observe(dockVertical, {
|
|||
|
|
attributes: true,
|
|||
|
|
attributeFilter: ["class"]
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 监听 body 结构变化,dock/dockVertical 变化时重新 observe
|
|||
|
|
new MutationObserver(() => {
|
|||
|
|
panelObserver.disconnect();
|
|||
|
|
dockVerticalObserverInstance.disconnect();
|
|||
|
|
observeDock();
|
|||
|
|
updateMargins();
|
|||
|
|
}).observe(document.body, { childList: true, subtree: true });
|
|||
|
|
|
|||
|
|
// 主题和页面加载时刷新
|
|||
|
|
window.addEventListener("load", updateMargins);
|
|||
|
|
document.addEventListener("themechange", updateMargins);
|
|||
|
|
|
|||
|
|
// 首次初始化
|
|||
|
|
observeDock();
|
|||
|
|
updateMargins();
|
|||
|
|
setTimeout(updateMargins, 500);
|
|||
|
|
setTimeout(updateMargins, 1000);
|
|||
|
|
|
|||
|
|
// 存储观察器实例以便后续清理
|
|||
|
|
if (isRight) {
|
|||
|
|
rightPanelObserver = panelObserver;
|
|||
|
|
dockVerticalObserver = dockVerticalObserverInstance;
|
|||
|
|
} else {
|
|||
|
|
leftPanelObserver = panelObserver;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清理顶栏合并状态的辅助函数
|
|||
|
|
*/
|
|||
|
|
export const cleanupTopbarMerge = () => {
|
|||
|
|
// 断开观察器
|
|||
|
|
if (rightPanelObserver) {
|
|||
|
|
rightPanelObserver.disconnect();
|
|||
|
|
rightPanelObserver = null;
|
|||
|
|
}
|
|||
|
|
if (leftPanelObserver) {
|
|||
|
|
leftPanelObserver.disconnect();
|
|||
|
|
leftPanelObserver = null;
|
|||
|
|
}
|
|||
|
|
if (dockVerticalObserver) {
|
|||
|
|
dockVerticalObserver.disconnect();
|
|||
|
|
dockVerticalObserver = null;
|
|||
|
|
}
|
|||
|
|
if (layoutCenterObserver) {
|
|||
|
|
layoutCenterObserver.disconnect();
|
|||
|
|
layoutCenterObserver = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重置边距(参考旧版本实现)
|
|||
|
|
document.querySelectorAll(".layout__center .layout-tab-bar--readonly").forEach(tabBar => {
|
|||
|
|
tabBar.style.marginRight = "0px";
|
|||
|
|
});
|
|||
|
|
document.querySelectorAll(".layout__center .layout-tab-bar:not(.layout-tab-bar--readonly)").forEach(tabBar => {
|
|||
|
|
tabBar.style.marginLeft = "0px";
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 清理全局变量
|
|||
|
|
if (window.updateTabBarsMargin) {
|
|||
|
|
window.updateTabBarsMargin = null;
|
|||
|
|
}
|
|||
|
|
if (window.updateTabBarsMarginLeft) {
|
|||
|
|
window.updateTabBarsMarginLeft = null;
|
|||
|
|
}
|
|||
|
|
if (window._tabBarsResizeObserver) {
|
|||
|
|
window._tabBarsResizeObserver.disconnect();
|
|||
|
|
window._tabBarsResizeObserver = null;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 初始化左右两侧的顶栏合并功能
|
|||
|
|
*/
|
|||
|
|
export const initTopbarMergeMargins = () => {
|
|||
|
|
initTabBarsMarginUnified("right");
|
|||
|
|
initTabBarsMarginUnified("left");
|
|||
|
|
|
|||
|
|
// layoutCenter observer 保留
|
|||
|
|
const layoutCenter = document.querySelector(".layout__center");
|
|||
|
|
if (layoutCenter) {
|
|||
|
|
let marginUpdateTimer = null;
|
|||
|
|
const resizeObserver = new MutationObserver(() => {
|
|||
|
|
if (marginUpdateTimer) return;
|
|||
|
|
marginUpdateTimer = requestAnimationFrame(() => {
|
|||
|
|
window.updateTabBarsMargin?.();
|
|||
|
|
window.updateTabBarsMarginLeft?.();
|
|||
|
|
marginUpdateTimer = null;
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
resizeObserver.observe(layoutCenter, { childList: true, subtree: true });
|
|||
|
|
layoutCenterObserver = resizeObserver;
|
|||
|
|
window._tabBarsResizeObserver = resizeObserver;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 初始化功能
|
|||
|
|
initTopbarMergeMargins();
|