沃梦达 / IT编程 / 前端开发 / 正文

js通过八个点 拖动改变div大小的实现方法

下面是“JS通过八个点拖动改变div大小的实现方法”的完整攻略。

下面是“JS通过八个点拖动改变div大小的实现方法”的完整攻略。

1. 需求分析

我们需要实现一个可以通过拖动八个点来改变一个 div 元素的大小的功能。最好的做法是使用原生 JavaScript 实现,而不是使用第三方类库,这样我们可以更好地理解背后的实现原理。

2. HTML 结构

首先,我们需要准备一个 div 元素,用于展示效果。具体的实现方法是通过在 div 元素上创建八个 span 元素,用于拖动改变 div 元素的大小。

<div class="box">
  <span class="point top-left"></span>
  <span class="point top"></span>
  <span class="point top-right"></span>
  <span class="point right"></span>
  <span class="point bottom-right"></span>
  <span class="point bottom"></span>
  <span class="point bottom-left"></span>
  <span class="point left"></span>
</div>

3. CSS 样式

接下来,我们需要为这些元素添加 CSS 样式。具体实现方式是为 box 和 point 添加相关样式,使其具有接下来我们需要的拖动效果。

.box {
  width: 200px;
  height: 200px;
  background-color: #f0f0f0;
  position: relative;
}

.point {
  width: 10px;
  height: 10px;
  background-color: #333;
  position: absolute;
}

.top-left {
  top: -5px;
  left: -5px;
  cursor: nw-resize;
}

.top {
  top: -5px;
  left: 50%;
  margin-left: -5px;
  cursor: n-resize;
}

.top-right {
  top: -5px;
  right: -5px;
  cursor: ne-resize;
}

.right {
  top: 50%;
  right: -5px;
  margin-top: -5px;
  cursor: e-resize;
}

.bottom-right {
  bottom: -5px;
  right: -5px;
  cursor: se-resize;
}

.bottom {
  bottom: -5px;
  left: 50%;
  margin-left: -5px;
  cursor: s-resize;
}

.bottom-left {
  bottom: -5px;
  left: -5px;
  cursor: sw-resize;
}

.left {
  top: 50%;
  left: -5px;
  margin-top: -5px;
  cursor: w-resize;
}

其中,box 元素使用了 position: relative;,使得 point 元素可以根据 box 元素进行定位。point 元素使用了 position: absolute;,为了脱离文档流,并且可以根据 box 元素进行定位。

在 point 元素中,我们对运用了不同的鼠标样式和定位方式,以实现不同方向的拖动效果。

4. JavaScript 代码实现

最后,我们需要编写 JavaScript 代码,为拖动点添加对应的事件监听器,以实现拖动大小的功能。

4.1 获取元素

首先,我们需要获取 box 和 point 元素,以便在后续的操作中使用。

var box = document.querySelector('.box');
var points = document.querySelectorAll('.point');

4.2 实现拖动

接下来,我们需要为每个拖动点添加事件监听器,以实现拖动效果。具体实现方式是监听鼠标的 mousedown、mousemove、mouseup 事件。

points.forEach(function(point) {
  point.addEventListener('mousedown', handleMouseDown);
});

function handleMouseDown(e) {
  var point = e.target;
  var startX = e.pageX;
  var startY = e.pageY;
  var startWidth = parseInt(getComputedStyle(box).width);
  var startHeight = parseInt(getComputedStyle(box).height);
  var startTop = parseInt(getComputedStyle(box).top);
  var startLeft = parseInt(getComputedStyle(box).left);

  document.addEventListener('mousemove', handleMouseMove);
  document.addEventListener('mouseup', handleMouseUp);

  function handleMouseMove(e) {
    var deltaX = e.pageX - startX;
    var deltaY = e.pageY - startY;

    switch (point.className) {
      case 'point top-left':
        box.style.width = startWidth - deltaX + 'px';
        box.style.height = startHeight - deltaY + 'px';
        box.style.top = startTop + deltaY + 'px';
        box.style.left = startLeft + deltaX + 'px';
        break;
      case 'point top':
        box.style.height = startHeight - deltaY + 'px';
        box.style.top = startTop + deltaY + 'px';
        break;
      case 'point top-right':
        box.style.width = startWidth + deltaX + 'px';
        box.style.height = startHeight - deltaY + 'px';
        box.style.top = startTop + deltaY + 'px';
        break;
      case 'point right':
        box.style.width = startWidth + deltaX + 'px';
        break;
      case 'point bottom-right':
        box.style.width = startWidth + deltaX + 'px';
        box.style.height = startHeight + deltaY + 'px';
        break;
      case 'point bottom':
        box.style.height = startHeight + deltaY + 'px';
        break;
      case 'point bottom-left':
        box.style.width = startWidth - deltaX + 'px';
        box.style.height = startHeight + deltaY + 'px';
        box.style.left = startLeft + deltaX + 'px';
        break;
      case 'point left':
        box.style.width = startWidth - deltaX + 'px';
        box.style.left = startLeft + deltaX + 'px';
        break;
      default:
        break;
    }

    e.stopPropagation();
    e.preventDefault();
  }

  function handleMouseUp(e) {
    document.removeEventListener('mousemove', handleMouseMove);
    document.removeEventListener('mouseup', handleMouseUp);
  }

  e.stopPropagation();
  e.preventDefault();
}

在上述代码中,我们首先为每个 point 元素添加了 mousedown 事件监听器,当鼠标按下时会触发 handleMouseDown 函数。在 handleMouseDown 函数中,我们获取了相关信息,如起始坐标、元素宽高以及位置,以备后续使用。我们还添加了 mousemove 和 mouseup 事件监听器,以在鼠标移动时改变box元素的大小和位置,并在鼠标松开时移除监听器。

在 handleMouseMove 函数中,我们根据不同拖动点的位置,添加不同的改变逻辑,此处使用了一系列 switch 来判断分支。在 handleMouseUp 函数中,我们移除了所有的事件监听器。

4.3 完整代码

最终的代码实现如下:

<div class="box">
  <span class="point top-left"></span>
  <span class="point top"></span>
  <span class="point top-right"></span>
  <span class="point right"></span>
  <span class="point bottom-right"></span>
  <span class="point bottom"></span>
  <span class="point bottom-left"></span>
  <span class="point left"></span>
</div>

<style>
.box {
  width: 200px;
  height: 200px;
  background-color: #f0f0f0;
  position: relative;
}

.point {
  width: 10px;
  height: 10px;
  background-color: #333;
  position: absolute;
}

.top-left {
  top: -5px;
  left: -5px;
  cursor: nw-resize;
}

.top {
  top: -5px;
  left: 50%;
  margin-left: -5px;
  cursor: n-resize;
}

.top-right {
  top: -5px;
  right: -5px;
  cursor: ne-resize;
}

.right {
  top: 50%;
  right: -5px;
  margin-top: -5px;
  cursor: e-resize;
}

.bottom-right {
  bottom: -5px;
  right: -5px;
  cursor: se-resize;
}

.bottom {
  bottom: -5px;
  left: 50%;
  margin-left: -5px;
  cursor: s-resize;
}

.bottom-left {
  bottom: -5px;
  left: -5px;
  cursor: sw-resize;
}

.left {
  top: 50%;
  left: -5px;
  margin-top: -5px;
  cursor: w-resize;
}
</style>

<script>
var box = document.querySelector('.box');
var points = document.querySelectorAll('.point');

points.forEach(function(point) {
  point.addEventListener('mousedown', handleMouseDown);
});

function handleMouseDown(e) {
  var point = e.target;
  var startX = e.pageX;
  var startY = e.pageY;
  var startWidth = parseInt(getComputedStyle(box).width);
  var startHeight = parseInt(getComputedStyle(box).height);
  var startTop = parseInt(getComputedStyle(box).top);
  var startLeft = parseInt(getComputedStyle(box).left);

  document.addEventListener('mousemove', handleMouseMove);
  document.addEventListener('mouseup', handleMouseUp);

  function handleMouseMove(e) {
    var deltaX = e.pageX - startX;
    var deltaY = e.pageY - startY;

    switch (point.className) {
      case 'point top-left':
        box.style.width = startWidth - deltaX + 'px';
        box.style.height = startHeight - deltaY + 'px';
        box.style.top = startTop + deltaY + 'px';
        box.style.left = startLeft + deltaX + 'px';
        break;
      case 'point top':
        box.style.height = startHeight - deltaY + 'px';
        box.style.top = startTop + deltaY + 'px';
        break;
      case 'point top-right':
        box.style.width = startWidth + deltaX + 'px';
        box.style.height = startHeight - deltaY + 'px';
        box.style.top = startTop + deltaY + 'px';
        break;
      case 'point right':
        box.style.width = startWidth + deltaX + 'px';
        break;
      case 'point bottom-right':
        box.style.width = startWidth + deltaX + 'px';
        box.style.height = startHeight + deltaY + 'px';
        break;
      case 'point bottom':
        box.style.height = startHeight + deltaY + 'px';
        break;
      case 'point bottom-left':
        box.style.width = startWidth - deltaX + 'px';
        box.style.height = startHeight + deltaY + 'px';
        box.style.left = startLeft + deltaX + 'px';
        break;
      case 'point left':
        box.style.width = startWidth - deltaX + 'px';
        box.style.left = startLeft + deltaX + 'px';
        break;
      default:
        break;
    }

    e.stopPropagation();
    e.preventDefault();
  }

  function handleMouseUp(e) {
    document.removeEventListener('mousemove', handleMouseMove);
    document.removeEventListener('mouseup', handleMouseUp);
  }

  e.stopPropagation();
  e.preventDefault();
}
</script>

示例说明

下面给出两个示例说明:

示例1

在简单的 HTML 网页上添加上述 HTML 结构、CSS 样式和 JavaScript 代码,我们可以看到一个可以通过八个点拖动改变大小的方框。

你可以访问这个示例网页,以体验具体效果。

示例2

假设我们要在 React 网站上添加该功能,具体实现方式如下:

我们需在 React 组件中添加上述 HTML 结构,并加载上述 CSS 样式。然后添加以下 JavaScript 代码实现拖动功能:

import React, { useRef } from 'react';

function Box() {
  const boxRef = useRef(null);
  const pointsRef = useRef([]);

  const handleMouseDown = e => {
    const point = e.target;
    const startX = e.pageX;
    const startY = e.pageY;
    const startWidth = parseInt(getComputedStyle(boxRef.current).width);
    const startHeight = parseInt(getComputedStyle(boxRef.current).height);
    const startTop = parseInt(getComputedStyle(boxRef.current).top);
    const startLeft = parseInt(getComputedStyle(boxRef.current).left);

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);

    function handleMouseMove(e) {
      const deltaX = e.pageX - startX;
      const deltaY = e.pageY - startY;

      switch (point.className) {
        case 'point top-left':
          boxRef.current.style.width = startWidth - deltaX + 'px';
          boxRef.current.style.height = startHeight - deltaY + 'px';
          boxRef.current.style.top = startTop + deltaY + 'px';
          boxRef.current.style.left = startLeft + deltaX + 'px';
          break;
        case 'point top':
          boxRef.current.style.height = startHeight - deltaY + 'px';
          boxRef.current.style.top = startTop + deltaY + 'px';
          break;
        case 'point top-right':
          boxRef.current.style.width = startWidth + deltaX + 'px';
          boxRef.current.style.height = startHeight - deltaY + 'px';
          boxRef.current.style.top = startTop + deltaY + 'px';
          break;
        case 'point right':
          boxRef.current.style.width = startWidth + deltaX + 'px';
          break;
        case 'point bottom-right':
          boxRef.current.style.width = startWidth + deltaX + 'px';
          boxRef.current.style.height = startHeight + deltaY + 'px';
          break;
        case 'point bottom':
          boxRef.current.style.height = startHeight + deltaY + 'px';
          break;
        case 'point bottom-left':
          boxRef.current.style.width = startWidth - deltaX + 'px';
          boxRef.current.style.height = startHeight + deltaY + 'px';
          boxRef.current.style.left = startLeft + deltaX + 'px';
          break;
        case 'point left':
          boxRef.current.style.width = startWidth - deltaX + 'px';
          boxRef.current.style.left = startLeft + deltaX + 'px';
          break;
        default:
          break;
      }

      e.stopPropagation();
      e.preventDefault();
    }

    function handleMouseUp(e) {
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
    }

    e.stopPropagation();
    e.preventDefault();
  };

  const handleBoxRef = reactElement => {
    boxRef.current = reactElement;
  };

  const handlePointsRef = (index, reactElement) => {
    pointsRef.current[index] = reactElement;
  };

  return (
    <div className="box" ref={handleBoxRef}>
      <span className="point top-left" ref={element => handlePointsRef(0, element)} onMouseDown={handleMouseDown} />
      <span className="point top" ref={element => handlePointsRef(1, element)} onMouseDown={handleMouseDown} />
      <span className="point top-right" ref={element => handlePointsRef(2, element)} onMouseDown={handleMouseDown} />
      <span className="point right" ref={element => handlePointsRef(3, element)} onMouseDown={handleMouseDown} />
      <span className="point bottom-right" ref={element => handlePointsRef(4, element)} onMouseDown={handleMouseDown} />
      <span className="point bottom" ref={element => handlePointsRef(5, element)} onMouseDown={handleMouseDown} />
      <span className="point bottom-left" ref={element => handlePointsRef(6, element)} onMouseDown={handleMouseDown} />
      <span className="point left" ref={element => handlePointsRef(7, element)} onMouseDown={handleMouseDown} />
    </div>
  );
}

此处我们使用了 React Hooks API 中的 useRef 来获取 box 和 point 元素,并为每个唯一的 point 元素分配了一个 ref。最终的效果和上面的普通 HTML 网页效果相同。

你可以访问这个示例网页,以查看完整的 React 实现例子。

本文标题为:js通过八个点 拖动改变div大小的实现方法