最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

原生JS實(shí)現(xiàn)雙欄布局拖拽的效果實(shí)例(附源碼)

 更新時(shí)間:2026年03月23日 10:59:39   作者:程序員大衛(wèi)  
在網(wǎng)頁開發(fā)中,拖拽功能是一種常見的交互行為,可以讓用戶通過鼠標(biāo)操作來拖動元素,這篇文章主要介紹了原生JS實(shí)現(xiàn)雙欄布局拖拽的效果實(shí)例,需要的朋友可以參考下

前言

之前有個老的項(xiàng)目,需要使用 jQuery 實(shí)現(xiàn)這種雙欄布局拖拽的效果,特此記錄一下,分享給大家。

實(shí)現(xiàn)思路講解

這個雙欄拖拽布局,本質(zhì)上只做了一件事:

通過拖拽中間的分割線,動態(tài)改變左側(cè)容器的寬度,右側(cè)自動填充剩余空間。

我們可以把整個實(shí)現(xiàn)拆成 4 個核心步驟 來理解。

一、整體布局結(jié)構(gòu)是關(guān)鍵

先看最核心的 DOM 結(jié)構(gòu)(簡化后):

<div class="content-container">
  <div class="left-container"></div>
  <div class="divider-container"></div>
  <div class="right-container"></div>
</div>

為什么要這樣結(jié)構(gòu)?

  • 父容器 .content-container 使用 flex
  • 左側(cè) .left-container 固定寬度(但可變)
  • 中間 .divider-container拖拽手柄
  • 右側(cè) .right-container 使用 flex-grow: 1 自動填充剩余空間

?? 重點(diǎn):我們只需要控制 left 的寬度,right 會自動變化

CSS 里最關(guān)鍵的幾行是:

.content-container {
  display: flex;
}

.left-container {
  flex-shrink: 0;
}

.right-container {
  flex-grow: 1;
}

二、拖拽的核心原理(一定要理解)

拖拽其實(shí)并不神秘,本質(zhì)只有 3 個事件:

  1. mousedown:開始拖拽
  2. mousemove:拖拽過程中,持續(xù)計(jì)算距離
  3. mouseup:結(jié)束拖拽

拖拽時(shí)我們關(guān)心什么?

只關(guān)心 鼠標(biāo)在 X 軸上移動了多少

當(dāng)前寬度 = 初始寬度 + (當(dāng)前鼠標(biāo) X - 按下時(shí)鼠標(biāo) X)

代碼里對應(yīng)的是這一段:

var startX = e.clientX;       // 鼠標(biāo)按下時(shí)的 X
var leftWidth = $left.width(); // 左側(cè)初始寬度

setLeftContainerWidth(leftWidth + e.clientX - startX);

三、為什么 mousemove 要綁定在 document 上?

這是一個非常重要的細(xì)節(jié),新手最容易踩坑。

$document.on("mousemove", onMousemove);
$document.on("mouseup", onMouseup);

如果綁定在 divider 上會怎樣?

  • 鼠標(biāo)一旦移動太快
  • 光標(biāo)離開 divider 區(qū)域
  • 拖拽立刻失效

?? 所以正確做法是綁定到 document,確保鼠標(biāo)在頁面任何地方都能繼續(xù)拖拽。

四、防止寬度“拖炸”的邊界控制

拖拽時(shí)一定要做 最大 / 最小寬度限制,否則:

  • 左邊會被拖成負(fù)數(shù)
  • 或者直接蓋住右側(cè)

這里用了一個非常關(guān)鍵的方法:

var setLeftContainerWidth = function (width) {
  var contentWidth = $content.width();
  var dividerWidth = $divider.width();
  var maxLeftWidth = contentWidth - dividerWidth;

  width = Math.min(width, maxLeftWidth);
  $left.width(width);
};

這里做了什么?

  • 最大寬度 = 父容器寬度 - 分割線寬度
  • 使用 Math.min 防止超過最大值

?? 這一步是拖拽體驗(yàn)是否“絲滑”的關(guān)鍵點(diǎn)之一

五、為什么要加body.dragging這個狀態(tài)?

當(dāng)拖拽開始時(shí):

$body.addClass("dragging");

結(jié)束時(shí):

$body.removeClass("dragging");

對應(yīng) CSS:

body.dragging {
  cursor: col-resize;
}

body.dragging .left-container,
body.dragging .right-container {
  pointer-events: none;
}

這一步解決了什么問題?

  1. 統(tǒng)一鼠標(biāo)樣式
  2. 防止 iframe / 內(nèi)部元素?fù)屨际髽?biāo)事件
  3. 避免拖拽中斷(尤其是老項(xiàng)目、復(fù)雜頁面)

?? 這是很多“看起來能拖,但偶爾會斷”的根本解決方案

六、雙擊 / ESC / 按鈕恢復(fù)布局的設(shè)計(jì)思路

為了讓體驗(yàn)更好,這里加了幾個「快捷恢復(fù)」方式:

點(diǎn)擊中間手柄,恢復(fù) 50%

recoverWidth();
function recoverWidth() {
  $left.width($content.width() / 2);
}

按 ESC 鍵恢復(fù)

$document.on("keydown", function (e) {
  if (e.key === "Escape") {
    recoverWidth();
  }
});

左右雙箭頭一鍵全屏

setLeftContainerWidth(0);           // 左邊隱藏
setLeftContainerWidth($content.width()); // 左邊全屏

并且配合 CSS 動畫:

.left-container.animating {
  transition: width 0.4s ease;
}

?? 這讓“程序員工具類頁面”的體驗(yàn)直接上一個檔次

七、實(shí)現(xiàn)這個功能的幾個核心關(guān)鍵點(diǎn)(必看)

如果你只記住下面 5 條,也能自己寫出來 ??

  1. 布局用 flex,只改左側(cè)寬度
  2. mousemove / mouseup 一定綁定 document
  3. 拖拽時(shí)要保存起始 X 和初始寬度
  4. 必須做最大 / 最小寬度限制
  5. 拖拽中禁用 pointer-events,防止事件丟失

最后

這個方案雖然用了 jQuery,但實(shí)現(xiàn)思路是完全通用的

  • 原生 JS
  • Vue / React
  • 甚至桌面端 WebView

只要你理解了「拖拽本質(zhì)是計(jì)算位移」,這個效果你以后隨手就能寫出來。

附源碼

github.com/zm8/wechat-…

相關(guān)文章

最新評論

许昌市| 新郑市| 竹山县| 南丹县| 常山县| 宁蒗| 壶关县| 霞浦县| 福州市| 宾川县| 西乌| 姜堰市| 宣城市| 乐都县| 射洪县| 仁寿县| 临猗县| 兰州市| 钦州市| 买车| 临邑县| 盐源县| 河南省| 永川市| 双桥区| 广汉市| 河西区| 三明市| 白朗县| 寻乌县| 龙里县| 鹤庆县| 桂阳县| 嵊州市| 建始县| 定州市| 波密县| 潢川县| 仙桃市| 精河县| 昂仁县|