经典windows窗口和容器布局切换

<!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>

  

posted @ 2026-10-21 12:04  华腾智算  阅读(4)  评论(0)    收藏  举报
https://damo.alibaba.com/ https://tianchi.aliyun.com/course?spm=5176.21206777.J_3941670930.5.87dc17c9BZNvLL