You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:优化JavaScript实现的文本框拖拽调整宽度功能

问题

需要实现两个并排textarea的拖拽调整宽度功能,参考双栏编辑器的拖拽效果,但现有代码存在拖拽不流畅、无法拖至全宽的问题,原代码如下:

<!DOCTYPE html>
<html>
<head>
  <title>Log Converter</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <style>
    #input,
    #output {
      height: 80vh;
    }

    * {
    box-sizing: border-box;
    }
    
    .bar {
        height: 90%;
        width: 2px;
        background-color: #ddd;
        cursor: w-resize;
    }
  </style>
</head>
<body class="bg-gray-100">
  <div class="container mx-auto mt-10 p-4">
    <div class="flex gap-2">
        <div class="w-full left">
          <div class="editor">
            <textarea id="input" class="w-full h-48 p-4 bg-white rounded" placeholder="Enter logs here..."></textarea>
          </div>
          <button class="btn bg-green-500 text-white px-4 py-2 mt-4" onclick="convertLogs()">Convert</button>
        </div>
        <div><div class="bar w-1" title="Click & Drug"></div></div>
        <div class="w-full right">
            <textarea id="output" class="w-full h-48 p-4 bg-white rounded" readonly></textarea>
        </div>
    </div>
  </div>
      
  <script>
    const left = document.querySelector(".left"),
          bar = document.querySelector(".bar");

    const drag = (e) => {
        left.style.width = (e.pageX + (bar.offsetWidth * 148)) + "px";
    }

    bar.addEventListener("mousedown", () => {
        document.addEventListener("mousemove", drag);
    })

    window.addEventListener("click", () => {
        document.removeEventListener("mousemove", drag);
    })
  </script>
</body>
</html>
解决方案

修改以下核心点即可解决问题:

  • 替换拖拽宽度计算逻辑:基于父容器的相对位置计算宽度,避免绝对坐标导致的偏移
  • 优化事件绑定:在mouseup事件中移除拖拽监听,而非click事件,防止拖拽中途意外停止
  • 添加边界限制:确保左右栏不会被拖到最小宽度以下或超出父容器范围
  • 调整拖拽栏布局:让拖拽栏高度匹配编辑器区域,提升交互体验

完整修正代码:

<!DOCTYPE html>
<html>
<head>
  <title>Log Converter</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <style>
    #input,
    #output {
      height: 80vh;
    }

    * {
      box-sizing: border-box;
    }
    
    .bar-container {
      display: flex;
      align-items: stretch;
    }

    .bar {
      width: 4px;
      background-color: #ddd;
      cursor: col-resize;
      margin: 0 4px;
      transition: background-color 0.2s;
    }

    .bar:hover {
      background-color: #999;
    }

    .left, .right {
      flex-shrink: 0;
      flex-grow: 1;
      min-width: 100px; /* 最小宽度限制,可调整 */
    }
  </style>
</head>
<body class="bg-gray-100">
  <div class="container mx-auto mt-10 p-4">
    <div class="flex gap-2 h-[80vh]">
        <div class="left w-1/2">
          <div class="editor h-full flex flex-col">
            <textarea id="input" class="flex-1 w-full p-4 bg-white rounded" placeholder="Enter logs here..."></textarea>
            <button class="btn bg-green-500 text-white px-4 py-2 mt-4" onclick="convertLogs()">Convert</button>
          </div>
        </div>
        <div class="bar-container">
          <div class="bar" title="拖拽调整宽度"></div>
        </div>
        <div class="right w-1/2">
            <textarea id="output" class="w-full h-full p-4 bg-white rounded" readonly></textarea>
        </div>
    </div>
  </div>
      
  <script>
    const left = document.querySelector(".left"),
          right = document.querySelector(".right"),
          bar = document.querySelector(".bar"),
          parent = bar.parentElement.parentElement; // 获取父容器

    let isDragging = false;

    const startDrag = () => {
        isDragging = true;
        document.body.style.cursor = "col-resize";
    };

    const stopDrag = () => {
        isDragging = false;
        document.body.style.cursor = "";
    };

    const drag = (e) => {
        if (!isDragging) return;
        
        // 计算父容器的左侧偏移
        const parentLeft = parent.getBoundingClientRect().left;
        // 计算左侧栏的宽度(鼠标位置 - 父容器左侧)
        let leftWidth = e.clientX - parentLeft;
        // 父容器总宽度
        const parentWidth = parent.offsetWidth;
        // 右侧栏最小宽度
        const minRightWidth = 100;

        // 边界限制:左侧栏不能太小,也不能让右侧栏小于最小宽度
        leftWidth = Math.max(100, Math.min(leftWidth, parentWidth - minRightWidth - bar.offsetWidth));
        
        left.style.width = `${leftWidth}px`;
        right.style.width = `${parentWidth - leftWidth - bar.offsetWidth - 8}px`; // 减去gap的2*4px
    };

    bar.addEventListener("mousedown", startDrag);
    document.addEventListener("mousemove", drag);
    document.addEventListener("mouseup", stopDrag);
  </script>
</body>
</html>

关键修改说明

  • 使用clientX替代pageX,结合父容器的getBoundingClientRect()计算相对宽度,避免页面滚动导致的偏移
  • 通过isDragging状态变量控制拖拽逻辑,避免无效触发
  • 添加min-width和最大宽度限制,防止栏被拖到不可用的范围
  • 调整拖拽栏的样式,增加hover效果提升交互反馈
  • 让左右栏使用flex布局,配合固定最小宽度,确保拖拽时布局稳定

内容的提问来源于stack exchange,提问作者Meshkat Hassan Riad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 08:36:13