假设我们要将以下元素变成可拖动元素:

<div id="resizeMe" class="resizable">Resize me</div>

首先,我们需要准备一些指示元素可调整大小的元素。它们绝对放置在原始元素的四个侧面。

为了演示简单,这里只准备了两个元素,分别放在左右两侧:

<div id="resizeMe" class="resizable">
  Resize me
  <div class="resizer resizer-r"></div>
  <div class="resizer resizer-b"></div>
</div>

以下是布局的基本样式:

.resizable {
  position: relative;
}

.resizer {
  /* 所有缩放器都绝对位于元素内部 */
  position: absolute;
}

/* 放在右边 */
.resizer-r {
  cursor: col-resize;
  height: 100%;
  right: 0;
  top: 0;
  width: 5px;
}

/* 放置在底部 */
.resizer-b {
  bottom: 0;
  cursor: row-resize;
  height: 5px;
  left: 0;
  width: 100%;
}

为了使元素可调整大小,我们将处理三个事件:

  • resizers 上使用 mousedown:跟踪鼠标的当前位置和原始元素的尺寸

  • document 上使用 mousemove:计算鼠标移动了多远,并调整元素的尺寸

  • document 上使用 mouseupon:删除 document 上的事件处理程序

const ele = document.getElementById('resizeMe')

// 鼠标当前位置
let x = 0
let y = 0

// 元素的维度
let w = 0
let h = 0

// 处理鼠标按下事件
// 当用户拖动 resizer 时触发
const mouseDownHandler = function (e) {
  // 获取当前鼠标位置
  x = e.clientX
  y = e.clientY

  // 计算元素的维度
  const styles = window.getComputedStyle(ele)
  w = parseInt(styles.width, 10)
  h = parseInt(styles.height, 10)

  // 将***附加到 document
  document.addEventListener('mousemove', mouseMoveHandler)
  document.addEventListener('mouseup', mouseUpHandler)
}

const mouseMoveHandler = function (e) {
  // 鼠标移动了多远
  const dx = e.clientX - x
  const dy = e.clientY - y

  // 调整元素的尺寸
  ele.style.width = `${w + dx}px`
  ele.style.height = `${h + dy}px`
}

const mouseUpHandler = function () {
  // 移除 mousemove 和 mouseup 的处理程序
  document.removeEventListener('mousemove', mouseMoveHandler)
  document.removeEventListener('mouseup', mouseUpHandler)
}

所有的事件处理程序都准备好了。最后,我们将 mousedown 事件处理程序附加到所有调整器:

const resizer = ele.querySelector('.resizer')
resizer.addEventListener("mousedown", mouseDownHandler)

查看效果