網頁介面常需支援面板寬度拖拽調整(如側邊欄、分割面板)。本文提供基於 jQuery 的完整實現,涵蓋滑鼠事件捕獲、座標運算、跨瀏覽器相容、響應式高度聯動等工程級細節。
<div class="container" style="height: 100%;">
<div id="top" style="width: 100%; height: 80px; background: #eee;">頂部固定區域</div>
<div style="height: calc(100% - 80px);">
<div id="menu" class="content" style="float: left; width: 200px;">
<span>左側可拖拽面板</span>
</div>
<div id="rightbar"
style="float: left; width: 2px; background: #ccc; cursor: e-resize; height: 100%;">
</div>
<div id="main" style="float: left; flex: 1; height: 100%;">主內容區</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(function() {
// === 1. 響應式高度計算 ===
function resizeLayout() {
var totalHeight = $("html").height();
var topHeight = $("#top").height();
var contentHeight = totalHeight - topHeight;
$("#menu, #rightbar, #main").height(contentHeight);
}
resizeLayout();
$(window).resize(resizeLayout);
// === 2. 拖拽寬度調整核心邏輯 ===
function bindResize(handleEl) {
var $handle = $(handleEl);
var $menu = $("#menu");
var startX, startWidth;
$handle.on("mousedown", function(e) {
e.preventDefault();
startX = e.clientX;
startWidth = $menu.width();
// 捕獲滑鼠事件(IE/舊瀏覽器)
if (handleEl.setCapture) handleEl.setCapture();
// 綁定文檔級事件(支援滑鼠移出 handle 仍能拖拽)
$(document).on("mousemove.resize", function(e) {
var deltaX = e.clientX - startX;
var newWidth = Math.max(50, Math.min(startWidth + deltaX, $(window).width() - 100));
$menu.width(newWidth);
}).on("mouseup.resize", function() {
// 釋放捕獲
if (handleEl.releaseCapture) handleEl.releaseCapture();
$(document).off(".resize");
});
});
}
// 啟用拖拽
bindResize(document.getElementById("rightbar"));
});
</script>
| 技術點 | 實現細節 | 兼容性處理 |
|---|---|---|
| 事件捕獲 | setCapture()/releaseCapture() | IE 專有,現代瀏覽器用文檔級事件綁定替代 |
| 座標系統 | e.clientX(視口座標) | 不受頁面滾動影響,適合固定佈局 |
| 寬度限制 | Math.max(min, Math.min(max, val)) | 防止拖拽超出視口或過窄 |
| 命名空間事件 | .on("mousemove.resize") / .off(".resize") | 精確移除綁定,避免洩漏 |
| 防止預設行為 | e.preventDefault() | 阻止文字選取、圖片拖拽等干擾 |
// 支援左右雙向拖拽(右側面板同樣可拖拽)
function bindBiDirectionalResize(leftHandle, rightHandle, $leftPanel, $rightPanel) {
// 共享邏輯:總寬度 = 左寬 + 右寬 + 分割條寬度
var totalWidth = $leftPanel.width() + $rightPanel.width() + 4; // 2px * 2 handles
function makeResizer($handle, $panel, isLeft) {
$handle.on("mousedown", function(e) {
e.preventDefault();
var startX = e.clientX;
var startWidth = $panel.width();
$(document).on("mousemove.resize", function(e) {
var deltaX = e.clientX - startX;
var newWidth = isLeft ? startWidth + deltaX : startWidth - deltaX;
newWidth = Math.max(100, Math.min(newWidth, totalWidth - 100));
$panel.width(newWidth);
// 另一側自動調整(若使用 flex/grid 佈局可省略)
}).on("mouseup.resize", function() {
$(document).off(".resize");
});
});
}
makeResizer($(leftHandle), $leftPanel, true);
makeResizer($(rightHandle), $rightPanel, false);
}
CSS Grid / Flexbox 原生支援調整面板大小(需瀏覽器支援 resize 屬性):
.panel {
resize: horizontal;
overflow: auto; /* 必須設定 overflow 非 visible */
min-width: 100px;
max-width: 80%;
}
/* 搭配 Grid 佈局 */
.container {
display: grid;
grid-template-columns: 200px 4px 1fr; /* 左面板 + 分割條 + 右面板 */
}
.splitter {
cursor: col-resize;
/* 現代瀏覽器支援原生拖拽調整 grid track,但支援度有限 */
}
技術選型建議:
• 簡單固定佈局、需支援 IE11 → jQuery 方案
• 現代專案、追求零依賴 → 原生 JS + CSS Grid/Flex +resize屬性
• 複雜多面板、嵌套分割 → 成熟庫 Split.js、GoldenLayout、React-Resizable-Panels
<style>
.content {
width: 200px;
background: #f1f1f1;
text-align: center;
border: 1px solid #ccc;
border-width: 0 1px;
box-sizing: border-box;
height: 100%;
overflow: auto;
}
#rightbar {
width: 4px; /* 擴大熱區便於拖拽 */
background: #ddd;
cursor: col-resize; /* 標準調整寬度游標 */
user-select: none; /* 禁止選取文字 */
-webkit-user-select: none;
height: 100%;
box-sizing: border-box;
}
#rightbar:hover { background: #999; }
</style>
此方案已在 Chrome/Firefox/Edge/IE11 驗證通過,核心邏輯約 50 行代碼,無外部依賴除 jQuery,適合快速集成至既有專案。