<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Windows 风格窗口 + FaLayoutContainer</title>
<style>
/* ============================================================
一、Element Plus 设计变量(内部布局容器使用)
============================================================ */
:root {
--el-color-primary: #409eff;
--el-color-primary-light-9: #ecf5ff;
--el-bg-color: #ffffff;
--el-bg-color-page: #f2f3f5;
--el-text-color-primary: #303133;
--el-text-color-regular: #606266;
--el-text-color-secondary: #909399;
--el-border-color: #dcdfe6;
--el-border-color-light: #e4e7ed;
--el-border-radius-base: 8px;
--el-border-radius-small: 4px;
--el-font-size-base: 14px;
--el-transition-duration: 0.3s;
--el-transition-function: cubic-bezier(0.4, 0, 0.2, 1);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
/* ============================================================
二、桌面背景(让窗口浮起来)
============================================================ */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
height: 100vh;
overflow: hidden;
/* 深色桌面渐变,衬托白色窗口 */
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 50%, #4b6cb7 100%);
}
/* ============================================================
三、Windows 风格窗口外壳
============================================================ */
.window-shell {
position: absolute;
width: 90vw;
max-width: 1400px;
height: 85vh;
max-height: 900px;
min-width: 720px;
min-height: 500px;
background: #ffffff;
border-radius: 10px;
box-shadow:
0 0 0 1px rgba(255, 255, 255, 0.1),
0 20px 60px rgba(0, 0, 0, 0.4),
0 8px 24px rgba(0, 0, 0, 0.25);
display: flex;
flex-direction: column;
overflow: hidden;
transition: opacity 0.3s, transform 0.3s, border-radius 0.3s,
width 0.3s, height 0.3s, left 0.3s, top 0.3s;
}
/* 最大化状态 */
.window-shell.is-maximized {
left: 0 !important;
top: 0 !important;
width: 100vw !important;
height: 100vh !important;
max-width: none;
max-height: none;
border-radius: 0;
}
/* 最小化状态:缩到左下角只剩标题栏 */
.window-shell.is-minimized {
left: 16px !important;
top: auto !important;
bottom: 16px !important;
width: 260px !important;
height: 40px !important;
min-width: 0;
min-height: 0;
border-radius: 8px;
cursor: pointer;
}
.window-shell.is-minimized .window-body { display: none; }
.window-shell.is-minimized .window-controls { display: none; }
.window-shell.is-minimized .window-titlebar {
cursor: pointer;
justify-content: center;
}
/* 关闭状态:淡出 */
.window-shell.is-closed {
opacity: 0;
transform: scale(0.92);
pointer-events: none;
}
/* ============================================================
四、标题栏(Win11 风格浅色标题栏)
============================================================ */
.window-titlebar {
flex-shrink: 0;
height: 40px;
display: flex;
align-items: center;
justify-content: space-between;
background: #f3f3f3;
border-bottom: 1px solid #e5e5e5;
padding-left: 12px;
user-select: none;
cursor: default;
}
.window-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 13px;
font-weight: 500;
color: #303133;
white-space: nowrap;
overflow: hidden;
}
.window-title .app-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.window-title .title-text {
overflow: hidden;
text-overflow: ellipsis;
}
/* 窗口控制按钮组 */
.window-controls {
display: flex;
height: 100%;
flex-shrink: 0;
}
.win-btn {
width: 46px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
cursor: pointer;
color: #333;
transition: background 0.15s, color 0.15s;
}
.win-btn:hover { background: #e5e5e5; }
.win-btn.close:hover { background: #e81123; color: #ffffff; }
.win-btn svg { width: 10px; height: 10px; display: block; }
/* ============================================================
五、窗口主体(承载内部布局容器)
============================================================ */
.window-body {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
padding: 16px;
gap: 12px;
background: var(--el-bg-color-page);
overflow: hidden;
}
/* 内部演示控制栏 */
.demo-controls {
flex-shrink: 0;
display: flex;
align-items: center;
gap: 12px;
font-size: 13px;
color: var(--el-text-color-regular);
}
.demo-controls button {
padding: 5px 12px;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-small);
background: var(--el-bg-color);
color: var(--el-text-color-regular);
cursor: pointer;
font-size: 13px;
transition: all 0.2s;
}
.demo-controls button:hover {
border-color: var(--el-color-primary);
color: var(--el-color-primary);
}
/* ============================================================
六、FaLayoutContainer 核心布局(左侧 | 中间(上-下) | 右侧)
============================================================ */
.layout-container {
display: flex;
flex: 1;
min-height: 0;
gap: 12px;
--left-width: 280px;
--right-width: 280px;
--top-height: 120px;
--bottom-height: 120px;
}
.middle-area {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 12px;
}
/* 所有卡片通用样式 */
.side-panel, .main-content {
background-color: var(--el-bg-color);
border: 1px solid var(--el-border-color-light);
border-radius: var(--el-border-radius-base);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
position: relative;
display: flex;
flex-direction: column;
transition: width var(--el-transition-duration) var(--el-transition-function),
height var(--el-transition-duration) var(--el-transition-function),
opacity var(--el-transition-duration) var(--el-transition-function),
border-radius var(--el-transition-duration) var(--el-transition-function);
overflow: visible;
}
.left-panel { width: var(--left-width); flex-shrink: 0; }
.right-panel { width: var(--right-width); flex-shrink: 0; }
.top-panel { height: var(--top-height); flex-shrink: 0; }
.bottom-panel { height: var(--bottom-height); flex-shrink: 0; }
.main-content { flex: 1; min-height: 0; }
/* 隐藏状态 */
.side-panel.is-hidden {
width: 0 !important;
height: 0 !important;
opacity: 0;
border-color: transparent;
margin: 0 -6px;
pointer-events: none;
}
/* 内容排版 */
.panel-header {
padding: 10px 14px;
font-weight: 600;
font-size: 13px;
border-bottom: 1px solid var(--el-border-color-light);
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
color: var(--el-text-color-primary);
}
.panel-body {
padding: 14px;
overflow-y: auto;
font-size: 13px;
line-height: 1.8;
color: var(--el-text-color-regular);
flex: 1;
}
.panel-body ul { list-style: none; padding: 0; }
.panel-body li { padding: 5px 8px; border-radius: 4px; }
.panel-body li:hover { background-color: var(--el-bg-color-page); }
/* ============================================================
七、半圆三角切换按钮
============================================================ */
.toggle-btn {
position: absolute;
z-index: 30;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--el-bg-color);
border: 1px solid var(--el-border-color);
color: var(--el-text-color-secondary);
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
padding: 0;
}
.toggle-btn:hover {
background-color: var(--el-color-primary-light-9);
color: var(--el-color-primary);
border-color: var(--el-color-primary);
}
.toggle-btn svg {
width: 14px;
height: 14px;
transition: transform var(--el-transition-duration);
}
.left-panel .toggle-btn {
right: -14px; top: 50%; transform: translateY(-50%);
width: 24px; height: 44px; border-radius: 0 22px 22px 0;
}
.right-panel .toggle-btn {
left: -14px; top: 50%; transform: translateY(-50%);
width: 24px; height: 44px; border-radius: 22px 0 0 22px;
}
.top-panel .toggle-btn {
bottom: -14px; left: 50%; transform: translateX(-50%);
width: 44px; height: 24px; border-radius: 0 0 22px 22px;
}
.bottom-panel .toggle-btn {
top: -14px; left: 50%; transform: translateX(-50%);
width: 44px; height: 24px; border-radius: 22px 22px 0 0;
}
/* 折叠后图标翻转 */
.side-panel.is-hidden .toggle-btn svg { transform: rotate(180deg); }
/* ============================================================
八、拖拽手柄(滑动调整)
============================================================ */
.resize-handle {
position: absolute;
z-index: 20;
background-color: transparent;
transition: background-color 0.2s;
}
.resize-handle:hover, .resize-handle.active {
background-color: var(--el-color-primary);
}
.left-panel .resize-handle { right: -3px; top: 0; bottom: 0; width: 6px; cursor: col-resize; }
.right-panel .resize-handle { left: -3px; top: 0; bottom: 0; width: 6px; cursor: col-resize; }
.top-panel .resize-handle { bottom: -3px; left: 0; right: 0; height: 6px; cursor: row-resize; }
.bottom-panel .resize-handle { top: -3px; left: 0; right: 0; height: 6px; cursor: row-resize; }
/* ============================================================
九、圆角联动(面板折叠时主内容区圆角恢复)
============================================================ */
.layout-container:has(.left-panel.is-hidden) .middle-area > .main-content {
border-top-left-radius: var(--el-border-radius-base);
border-bottom-left-radius: var(--el-border-radius-base);
}
.layout-container:has(.right-panel.is-hidden) .middle-area > .main-content {
border-top-right-radius: var(--el-border-radius-base);
border-bottom-right-radius: var(--el-border-radius-base);
}
.middle-area:has(.top-panel.is-hidden) .main-content {
border-top-left-radius: var(--el-border-radius-base);
border-top-right-radius: var(--el-border-radius-base);
}
.middle-area:has(.bottom-panel.is-hidden) .main-content {
border-bottom-left-radius: var(--el-border-radius-base);
border-bottom-right-radius: var(--el-border-radius-base);
}
/* ============================================================
十、垂直布局切换
============================================================ */
.layout-container.is-vertical { flex-direction: column; }
.layout-container.is-vertical .middle-area { flex-direction: row; }
.layout-container.is-vertical .left-panel,
.layout-container.is-vertical .right-panel {
width: 100%; height: auto; flex-shrink: 0;
}
.layout-container.is-vertical .left-panel { height: var(--left-width); }
.layout-container.is-vertical .right-panel { height: var(--right-width); }
.layout-container.is-vertical .top-panel { width: var(--top-height); height: 100%; flex-shrink: 0; }
.layout-container.is-vertical .bottom-panel { width: var(--bottom-height); height: 100%; flex-shrink: 0; }
/* 垂直模式下按钮重定位 */
.layout-container.is-vertical .left-panel .toggle-btn {
right: auto; bottom: -14px; left: 50%; top: auto; transform: translateX(-50%);
width: 44px; height: 24px; border-radius: 0 0 22px 22px;
}
.layout-container.is-vertical .right-panel .toggle-btn {
left: 50%; bottom: -14px; top: auto; transform: translateX(-50%);
width: 44px; height: 24px; border-radius: 22px 22px 0 0;
}
.layout-container.is-vertical .top-panel .toggle-btn {
bottom: auto; right: -14px; top: 50%; left: auto; transform: translateY(-50%);
width: 24px; height: 44px; border-radius: 22px 0 0 22px;
}
.layout-container.is-vertical .bottom-panel .toggle-btn {
top: 50%; right: -14px; left: auto; transform: translateY(-50%);
width: 24px; height: 44px; border-radius: 0 22px 22px 0;
}
/* ============================================================
十一、重新打开窗口按钮(关闭后出现)
============================================================ */
.reopen-btn {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 12px 28px;
background: #ffffff;
border: 1px solid var(--el-border-color);
border-radius: 8px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
font-size: 14px;
color: var(--el-color-primary);
cursor: pointer;
display: none;
align-items: center;
gap: 8px;
transition: all 0.2s;
z-index: 9999;
}
.reopen-btn:hover {
background: var(--el-color-primary-light-9);
border-color: var(--el-color-primary);
}
</style>
</head>
<body>
<!-- ============================================================
最外层:Windows 风格窗口
============================================================ -->
<div class="window-shell" id="windowShell">
<!-- 标题栏 -->
<div class="window-titlebar" id="windowTitlebar">
<div class="window-title">
<!-- 应用图标:四个彩色小方块,象征布局 -->
<svg class="app-icon" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1" width="6" height="6" rx="1" fill="#409eff"/>
<rect x="9" y="1" width="6" height="6" rx="1" fill="#67c23a"/>
<rect x="1" y="9" width="6" height="6" rx="1" fill="#e6a23c"/>
<rect x="9" y="9" width="6" height="6" rx="1" fill="#f56c6c"/>
</svg>
<span class="title-text">FaLayoutContainer 布局容器 — 窗口演示</span>
</div>
<div class="window-controls">
<button class="win-btn" id="btnMinimize" title="最小化">
<svg viewBox="0 0 10 10"><path d="M0 5h10" stroke="currentColor" stroke-width="1" fill="none"/></svg>
</button>
<button class="win-btn" id="btnMaximize" title="最大化">
<svg viewBox="0 0 10 10">
<rect x="0.5" y="0.5" width="9" height="9" fill="none" stroke="currentColor" stroke-width="1"/>
</svg>
</button>
<button class="win-btn close" id="btnClose" title="关闭">
<svg viewBox="0 0 10 10">
<path d="M0 0l10 10M10 0L0 10" stroke="currentColor" stroke-width="1" fill="none"/>
</svg>
</button>
</div>
</div>
<!-- 窗口主体:包含 FaLayoutContainer 及演示控件 -->
<div class="window-body">
<!-- 演示控制栏 -->
<div class="demo-controls">
<button id="toggleVerticalBtn">切换为垂直布局</button>
<span>拖动面板边缘滑动调整尺寸;点击半圆三角图标折叠/展开</span>
</div>
<!-- ================= 布局容器 ================= -->
<div class="layout-container" id="layoutContainer">
<!-- 1. 左侧面板 -->
<aside class="side-panel left-panel" id="leftPanel">
<div class="panel-header"><span>左侧面板</span></div>
<div class="panel-body">
<p>宽度默认 280px,可拖动右边缘调整。</p>
<ul style="margin-top: 8px;">
<li>仪表盘</li>
<li>用户管理</li>
<li>系统设置</li>
</ul>
</div>
<div class="resize-handle" data-resize="left"></div>
<button class="toggle-btn" data-toggle="left" aria-label="切换左侧面板">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" opacity="0.4" d="M2 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h2V4H2z"/>
<path fill="currentColor" d="M10 8l-4 4 4 4V8z"/>
</svg>
</button>
</aside>
<!-- 2. 中间区域:上-主-下 -->
<div class="middle-area">
<!-- 2.1 顶部面板 -->
<aside class="side-panel top-panel" id="topPanel">
<div class="panel-header"><span>顶部面板</span></div>
<div class="panel-body">
<p>高度默认 120px,可拖动下边缘调整。</p>
</div>
<div class="resize-handle" data-resize="top"></div>
<button class="toggle-btn" data-toggle="top" aria-label="切换顶部面板">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" opacity="0.4" d="M4 2a2 2 0 0 0-2 2v2h20V4a2 2 0 0 0-2-2H4z"/>
<path fill="currentColor" d="M8 10l4-4 4 4H8z"/>
</svg>
</button>
</aside>
<!-- 2.2 主内容区 -->
<main class="main-content">
<div class="panel-header"><span>主内容区(default 插槽)</span></div>
<div class="panel-body">
<p>主内容区由 <code>flex: 1</code> 自动填满中间区域剩余空间。</p>
<p>试试拖动四周面板边缘、点击半圆三角图标、切换垂直布局,观察平滑过渡。</p>
</div>
</main>
<!-- 2.3 底部面板 -->
<aside class="side-panel bottom-panel" id="bottomPanel">
<div class="panel-header"><span>底部面板</span></div>
<div class="panel-body">
<p>高度默认 120px,可拖动上边缘调整。</p>
</div>
<div class="resize-handle" data-resize="bottom"></div>
<button class="toggle-btn" data-toggle="bottom" aria-label="切换底部面板">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" opacity="0.4" d="M4 22a2 2 0 0 1-2-2v-2h20v2a2 2 0 0 1-2 2H4z"/>
<path fill="currentColor" d="M8 14l4 4 4-4H8z"/>
</svg>
</button>
</aside>
</div>
<!-- 3. 右侧面板 -->
<aside class="side-panel right-panel" id="rightPanel">
<div class="panel-header"><span>右侧面板</span></div>
<div class="panel-body">
<p>宽度默认 280px,可拖动左边缘调整。</p>
</div>
<div class="resize-handle" data-resize="right"></div>
<button class="toggle-btn" data-toggle="right" aria-label="切换右侧面板">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" opacity="0.4" d="M22 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-2V4h2z"/>
<path fill="currentColor" d="M14 8l4 4-4 4V8z"/>
</svg>
</button>
</aside>
</div>
</div>
</div>
<!-- 关闭后出现的“重新打开”按钮 -->
<button class="reopen-btn" id="reopenBtn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 12a9 9 0 1 0 3-6.7L3 8"/>
<path d="M3 3v5h5"/>
</svg>
重新打开窗口
</button>
<script>
/* ============================================================
零、元素引用
============================================================ */
const windowShell = document.getElementById('windowShell');
const windowTitlebar = document.getElementById('windowTitlebar');
const btnMinimize = document.getElementById('btnMinimize');
const btnMaximize = document.getElementById('btnMaximize');
const btnClose = document.getElementById('btnClose');
const reopenBtn = document.getElementById('reopenBtn');
/* ============================================================
一、窗口初始化居中
============================================================ */
function centerWindow() {
const left = (window.innerWidth - windowShell.offsetWidth) / 2;
const top = (window.innerHeight - windowShell.offsetHeight) / 2;
windowShell.style.left = left + 'px';
windowShell.style.top = Math.max(20, top) + 'px';
}
window.addEventListener('load', centerWindow);
window.addEventListener('resize', () => {
// 非最大化、非最小化时,窗口重新居中
if (!windowShell.classList.contains('is-maximized') &&
!windowShell.classList.contains('is-minimized') &&
!windowShell.classList.contains('is-closed')) {
centerWindow();
}
});
/* ============================================================
二、拖动窗口(按住标题栏拖动)
============================================================ */
let dragging = false;
let dragStartX = 0, dragStartY = 0;
let winStartLeft = 0, winStartTop = 0;
windowTitlebar.addEventListener('mousedown', (e) => {
// 最大化 / 最小化状态下不允许拖动;点击控制按钮区域也不拖
if (windowShell.classList.contains('is-maximized')) return;
if (windowShell.classList.contains('is-minimized')) return;
if (e.target.closest('.window-controls')) return;
dragging = true;
dragStartX = e.clientX;
dragStartY = e.clientY;
winStartLeft = windowShell.offsetLeft;
winStartTop = windowShell.offsetTop;
document.body.style.userSelect = 'none';
});
document.addEventListener('mousemove', (e) => {
if (!dragging) return;
const dx = e.clientX - dragStartX;
const dy = e.clientY - dragStartY;
// 限制窗口不能被拖出屏幕上边缘
windowShell.style.left = (winStartLeft + dx) + 'px';
windowShell.style.top = Math.max(0, winStartTop + dy) + 'px';
});
document.addEventListener('mouseup', () => {
if (dragging) {
dragging = false;
document.body.style.userSelect = '';
}
});
/* ============================================================
三、双击标题栏 → 切换最大化
============================================================ */
windowTitlebar.addEventListener('dblclick', (e) => {
if (e.target.closest('.window-controls')) return;
toggleMaximize();
});
/* ============================================================
四、最大化 / 还原
============================================================ */
function toggleMaximize() {
const willMaximize = !windowShell.classList.contains('is-maximized');
windowShell.classList.toggle('is-maximized', willMaximize);
// 更新按钮图标
if (willMaximize) {
// 还原图标(两个重叠方框)
btnMaximize.innerHTML = `
<svg viewBox="0 0 10 10">
<rect x="0.5" y="2.5" width="7" height="7" fill="none" stroke="currentColor" stroke-width="1"/>
<path d="M2.5 2.5V0.5h7v7h-2" fill="none" stroke="currentColor" stroke-width="1"/>
</svg>`;
btnMaximize.title = '还原';
} else {
// 最大化图标(单方框)
btnMaximize.innerHTML = `
<svg viewBox="0 0 10 10">
<rect x="0.5" y="0.5" width="9" height="9" fill="none" stroke="currentColor" stroke-width="1"/>
</svg>`;
btnMaximize.title = '最大化';
// 还原时重新居中
centerWindow();
}
}
btnMaximize.addEventListener('click', toggleMaximize);
/* ============================================================
五、最小化
============================================================ */
btnMinimize.addEventListener('click', () => {
windowShell.classList.add('is-minimized');
});
// 最小化状态下,点击窗口恢复
windowShell.addEventListener('click', (e) => {
if (windowShell.classList.contains('is-minimized')) {
// 点击控制按钮不恢复(其实最小化时控制按钮已隐藏,这里防御性判断)
if (e.target.closest('.window-controls')) return;
windowShell.classList.remove('is-minimized');
centerWindow();
}
});
/* ============================================================
六、关闭与重新打开
============================================================ */
btnClose.addEventListener('click', () => {
windowShell.classList.add('is-closed');
reopenBtn.style.display = 'flex';
});
reopenBtn.addEventListener('click', () => {
windowShell.classList.remove('is-closed');
reopenBtn.style.display = 'none';
// 关闭前若是最小化,重新打开时恢复默认尺寸
windowShell.classList.remove('is-minimized');
centerWindow();
});
/* ============================================================
七、内部 FaLayoutContainer 逻辑
============================================================ */
const container = document.getElementById('layoutContainer');
const panels = {
left: document.getElementById('leftPanel'),
right: document.getElementById('rightPanel'),
top: document.getElementById('topPanel'),
bottom: document.getElementById('bottomPanel')
};
const toggleVerticalBtn = document.getElementById('toggleVerticalBtn');
/* ---- 折叠 / 展开 ---- */
function togglePanel(key) {
const panel = panels[key];
if (!panel) return;
panel.classList.toggle('is-hidden');
const handle = panel.querySelector('.resize-handle');
if (handle) {
handle.style.display = panel.classList.contains('is-hidden') ? 'none' : '';
}
}
document.querySelectorAll('[data-toggle]').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
togglePanel(btn.dataset.toggle);
});
});
/* ---- 垂直布局切换 ---- */
toggleVerticalBtn.addEventListener('click', () => {
container.classList.toggle('is-vertical');
const isVertical = container.classList.contains('is-vertical');
toggleVerticalBtn.textContent = isVertical ? '切换为水平布局' : '切换为垂直布局';
Object.keys(panels).forEach(key => {
const handle = panels[key].querySelector('.resize-handle');
if (handle && panels[key].classList.contains('is-hidden')) {
handle.style.display = 'none';
}
});
});
/* ---- 拖拽调整尺寸 ---- */
document.querySelectorAll('.resize-handle').forEach(handle => {
handle.addEventListener('mousedown', (e) => {
e.preventDefault();
const key = handle.dataset.resize;
const panel = panels[key];
if (!panel || panel.classList.contains('is-hidden')) return;
const startX = e.clientX;
const startY = e.clientY;
const isVerticalMode = container.classList.contains('is-vertical');
const computed = getComputedStyle(container);
const startLeftWidth = parseFloat(computed.getPropertyValue('--left-width')) || 280;
const startRightWidth = parseFloat(computed.getPropertyValue('--right-width')) || 280;
const startTopHeight = parseFloat(computed.getPropertyValue('--top-height')) || 120;
const startBottomHeight = parseFloat(computed.getPropertyValue('--bottom-height')) || 120;
handle.classList.add('active');
function onMouseMove(ev) {
const deltaX = ev.clientX - startX;
const deltaY = ev.clientY - startY;
let newValue;
if (!isVerticalMode) {
if (key === 'left') {
newValue = Math.max(60, Math.min(startLeftWidth + deltaX, 800));
container.style.setProperty('--left-width', newValue + 'px');
} else if (key === 'right') {
newValue = Math.max(60, Math.min(startRightWidth - deltaX, 800));
container.style.setProperty('--right-width', newValue + 'px');
} else if (key === 'top') {
newValue = Math.max(40, Math.min(startTopHeight + deltaY, 500));
container.style.setProperty('--top-height', newValue + 'px');
} else if (key === 'bottom') {
newValue = Math.max(40, Math.min(startBottomHeight - deltaY, 500));
container.style.setProperty('--bottom-height', newValue + 'px');
}
} else {
if (key === 'left') {
newValue = Math.max(40, Math.min(startLeftWidth + deltaY, 500));
container.style.setProperty('--left-width', newValue + 'px');
} else if (key === 'right') {
newValue = Math.max(40, Math.min(startRightWidth - deltaY, 500));
container.style.setProperty('--right-width', newValue + 'px');
} else if (key === 'top') {
newValue = Math.max(60, Math.min(startTopHeight + deltaX, 800));
container.style.setProperty('--top-height', newValue + 'px');
} else if (key === 'bottom') {
newValue = Math.max(60, Math.min(startBottomHeight - deltaX, 800));
container.style.setProperty('--bottom-height', newValue + 'px');
}
}
}
function onMouseUp() {
handle.classList.remove('active');
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
document.body.style.cursor = '';
document.body.style.userSelect = '';
}
document.body.style.cursor = (key === 'left' || key === 'right') ? 'col-resize' : 'row-resize';
document.body.style.userSelect = 'none';
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
});
</script>
</body>
</html>