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

纯JS实现盒子宽度调整:左侧拉伸位置跳动问题求助

解决拖拽盒子左侧调整宽度时的位置跳动问题

问题根源

你在左侧调整宽度时,错误地使用盒子的初始宽度divWidth计算left属性值,完全偏离了盒子位置的实际变化逻辑,导致位置跳动。正确逻辑应该基于盒子的初始左侧位置和鼠标移动量,同步更新宽度与位置。

修正方案

  1. 在左侧手柄的mousedown事件中,额外记录盒子的初始左侧位置:
wlSize.addEventListener('mousedown', function(e){
  wlSizeDown = true;
  wlSizeOffset = {
    x: e.clientX,
    y: e.clientY
  }
  divWidth = parseInt(div.style.width, 10);
  // 新增:记录盒子初始left值
  divLeft = parseInt(div.style.left, 10);
});
  1. 修改mousemove事件中左侧调整的逻辑,基于鼠标移动量同步更新宽度和位置:
if(wlSizeDown){
  // 计算鼠标水平移动量
  const deltaX = mousePosition.x - wlSizeOffset.x;
  // 宽度 = 初始宽度 - 移动量(左移时移动量为负,宽度增加;右移时移动量为正,宽度减少)
  div.style.width = (divWidth - deltaX) + 'px';
  // 左侧位置 = 初始left + 移动量(左移时位置左移,右移时位置右移)
  div.style.left = (divLeft + deltaX) + 'px';
}

完整修正代码

var mousePosition;
var offset;
var wrSizeOffset, wlSizeOffset, hbSizeOffset;
var div;
var isDown = false;
var wlSizeDown, wrSizeDown, htSizeDown, hbSizeDown = false;
var divWidth, divHeight, divLeft; // 新增divLeft变量

div = document.createElement('div');
div.style.position = 'relative';
div.style.left = '100px';
div.style.top = '100px';
div.style.width = '100px';
div.style.height = '100px';
div.style.backgroundColor = 'red';
div.style.border = '1px solid black';

wrSize = document.createElement('div');
wrSize.style.position = 'absolute';
wrSize.style.right = '-10px';
wrSize.style.top = '40px';
wrSize.style.width = '20px';
wrSize.style.height = '20px';
wrSize.style.backgroundColor = 'black';
wrSize.style.border = '1px solid black';

wlSize = document.createElement('div');
wlSize.style.position = 'absolute';
wlSize.style.left = '-10px';
wlSize.style.top = '40px';
wlSize.style.width = '20px';
wlSize.style.height = '20px';
wlSize.style.backgroundColor = 'black';
wlSize.style.border = '1px solid black';

htSize = document.createElement('div');
htSize.style.position = 'absolute';
htSize.style.left = '40px';
htSize.style.top = '-10px';
htSize.style.width = '20px';
htSize.style.height = '20px';
htSize.style.backgroundColor = 'black';
htSize.style.border = '1px solid black';

hbSize = document.createElement('div');
hbSize.style.position = 'absolute';
hbSize.style.left = '40px';
hbSize.style.bottom = '-10px';
hbSize.style.width = '20px';
hbSize.style.height = '20px';
hbSize.style.backgroundColor = 'black';
hbSize.style.border = '1px solid black';

document.body.appendChild(div);
div.appendChild(wrSize);
div.appendChild(wlSize);
div.appendChild(htSize);
div.appendChild(hbSize);

div.addEventListener('mousedown', function(e){
  isDown = true;
  offset = {
    x: div.offsetLeft - e.clientX,
    y: div.offsetTop - e.clientY
  }
});

wrSize.addEventListener('mousedown', function(e){
  wrSizeDown = true;
  wrSizeOffset = {
    x: e.clientX,
    y: e.clientY
  }
  divWidth = parseInt(div.style.width, 10);
});

wlSize.addEventListener('mousedown', function(e){
  wlSizeDown = true;
  wlSizeOffset = {
    x: e.clientX,
    y: e.clientY
  }
  divWidth = parseInt(div.style.width, 10);
  divLeft = parseInt(div.style.left, 10); // 记录初始left
});

hbSize.addEventListener('mousedown', function(e){
  hbSizeDown = true;
  hbSizeOffset = {
    x: e.clientX,
    y: e.clientY
  }
  divHeight = parseInt(div.style.height, 10);
});

document.addEventListener('mouseup', function(e){
  isDown = false;
  wrSizeDown = false;
  wlSizeDown = false;
  hbSizeDown = false;
});

document.addEventListener('mousemove', function(e){
  mousePosition = {
    x: e.clientX,
    y: e.clientY
  }

  if(isDown && (!wrSizeDown && !wlSizeDown && !hbSizeDown)){
    div.style.left = (mousePosition.x + offset.x) + 'px';
    div.style.top = (mousePosition.y + offset.y) + 'px';
  }

  if(wrSizeDown){
    div.style.width = divWidth + mousePosition.x - wrSizeOffset.x + 'px';
  }

  if(hbSizeDown){
    div.style.height = divHeight + mousePosition.y - hbSizeOffset.y + 'px';
  }

  if(wlSizeDown){
    const deltaX = mousePosition.x - wlSizeOffset.x;
    div.style.width = (divWidth - deltaX) + 'px';
    div.style.left = (divLeft + deltaX) + 'px';
  }
});
body {
  margin: 0px;
}

* {
  box-sizing: border-box;
}

#box{
  position: absolute;
  display: block;
  top: 50px;
  left: 50px;
  width: 200px;
  height: 200px;
  background-color: #d80000;
  border: 1px solid #000;
}

补充说明

若要实现顶部调整高度的功能,逻辑与左侧调整一致:

  1. 在顶部手柄的mousedown事件中记录初始top值和初始高度
  2. 在mousemove中计算垂直移动量deltaY,更新高度divHeight - deltaY和top值divTop + deltaY

内容的提问来源于stack exchange,提问作者FarrisFahad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:54:56