Vue3 实现元素拖拽,缩放功能

<template>
  <div id="resizableDiv" ref="draggableBox" :style="{ top: top + 'px', left: left + 'px' }" @mousedown="startDrag" class="resizable-div">
    <div class="resize-handle top" data-direction="top"></div>
    <div class="resize-handle right" data-direction="right"></div>
    <div class="resize-handle bottom" data-direction="bottom"></div>
    <div class="resize-handle left" data-direction="left"></div>
    <div class="content">拖拽区域的内容</div>
  </div>
</template>

<script setup>
import {onMounted, onUnmounted, ref} from "vue";

const draggableBox = ref(null);
const top = ref(200); // 元素距离顶部的位置
const left = ref(200); // 元素距离左边的位置
let isDragging = false; // 是否正在拖拽
let offsetX = 0; // 鼠标点击点距离元素左上角的偏移
let offsetY = 0; // 鼠标点击点距离元素左上角的偏移

// 鼠标按下时开始拖拽
const startDrag = (event) => {
  isDragging = true;
  offsetX = event.clientX - left.value;
  offsetY = event.clientY - top.value;

  // 添加mousemove和mouseup事件监听
  document.addEventListener('mousemove', handleDrag);
  document.addEventListener('mouseup', stopDrag);
};

// 鼠标移动时拖拽元素
const handleDrag = (event) => {
  if (isDragging) {
    left.value = event.clientX - offsetX;
    top.value = event.clientY - offsetY;

    // 限制元素不超出可视区域
    const maxX = window.innerWidth - 20; // 假设可视区域宽度为窗口宽度减去100
    const maxY = window.innerHeight - 20; // 假设可视区域高度为窗口高度减去100
    left.value = Math.min(maxX, Math.max(0, left.value));
    if (left.value > window.innerWidth - draggableBox.value.clientWidth - 5) {
      left.value = window.innerWidth - draggableBox.value.clientWidth - 5
    }
    top.value = Math.min(maxY, Math.max(0, top.value));
    if (top.value > window.innerHeight - draggableBox.value.clientHeight - 5) {
      top.value = window.innerHeight - draggableBox.value.clientHeight - 5
    }
  }
};

// 鼠标松开时停止拖拽
const stopDrag = () => {
  isDragging = false;
  document.removeEventListener('mousemove', handleDrag);
  document.removeEventListener('mouseup', stopDrag);
};


onUnmounted(() => {
  // 在组件销毁前移除事件监听等资源
  document.removeEventListener('mousemove', handleDrag);
  document.removeEventListener('mouseup', stopDrag);
});

onMounted(() => {
  const resizableDiv = document.getElementById('resizableDiv');
  const resizeHandles = resizableDiv.querySelectorAll('.resize-handle');

  let isResizing = false;
  let currentHandle;

  resizeHandles.forEach(handle => {
    handle.addEventListener('mousedown', (e) => {
      isResizing = true;
      currentHandle = e.target.dataset.direction;
      e.stopPropagation()
    });
  });

  document.addEventListener('mousemove', (e) => {
    if (!isResizing) return;

    if (currentHandle) {
      if (currentHandle === 'right') {
        resizableDiv.style.width = e.clientX - resizableDiv.getBoundingClientRect().left + 'px';
      } else if (currentHandle === 'bottom') {
        resizableDiv.style.height = e.clientY - resizableDiv.getBoundingClientRect().top + 'px';
      } else if (currentHandle === 'left') {
        const originalWidth = resizableDiv.getBoundingClientRect().right - resizableDiv.getBoundingClientRect().left;
        const newWidth = resizableDiv.getBoundingClientRect().right - e.clientX;
        resizableDiv.style.left = e.clientX + 'px';
        resizableDiv.style.width = originalWidth + newWidth + 'px';
      } else if (currentHandle === 'top') {
        const originalHeight = resizableDiv.getBoundingClientRect().bottom - resizableDiv.getBoundingClientRect().top;
        const newHeight = resizableDiv.getBoundingClientRect().bottom - e.clientY;
        resizableDiv.style.top = e.clientY + 'px';
        resizableDiv.style.height = originalHeight + newHeight + 'px';
      }
    }
  });

  document.addEventListener('mouseup', () => {
    isResizing = false;
    currentHandle = null;
  });
})
</script>

<style lang="less">
.resizable-div {
  position: absolute;
  width: 200px;
  height: 200px;
  border: 2px solid #333;
  user-select: none;
  display: flex;
  flex-direction: column;
}

.resize-handle {
  position: absolute;
  background-color: #007bff;
  cursor: pointer;
}

.resize-handle.top {
  width: 100%;
  height: 2px;
  left: 0;
  top: -2px;
}

.resize-handle.right {
  height: 100%;
  width: 2px;
  top: 0;
  right: -2px;
}

.resize-handle.bottom {
  width: 100%;
  height: 2px;
  left: 0;
  bottom: -2px;
}

.resize-handle.left {
  height: 100%;
  width: 2px;
  top: 0;
  left: -2px;
}

.content {
  flex-grow: 1;
  background-color: #f0f0f0;
  padding: 10px;
}

</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用 Vue.js 和一些第三方库来实现组件,以下是一个基本的实现步骤: 1. 安装第三方库,例如 vue-draggable-resizable 或 vue-draggable 。 2. 在 Vue 组件中引入库并注册组件。 3. 在模板中使用组件,并设置组件的初始位置和大小。 4. 通过组件的事件监听器来跟踪组件的位置和大小变化,并在 Vue 实例中更新组件的状态。 5. 根据组件的状态来动态更新组件的样式和位置。 以下是一个简单的示例代码: ```html <template> <div> <vue-draggable-resizable :x="x" :y="y" :w="w" :h="h" :min-width="100" :min-height="100" :active.sync="isActive" :draggable="true" :resizable="true" @dragging="onDragging" @resizing="onResizing" > <div class="content">可元素</div> </vue-draggable-resizable> </div> </template> <script> import VueDraggableResizable from 'vue-draggable-resizable' export default { components: { VueDraggableResizable }, data() { return { x: 0, y: 0, w: 200, h: 200, isActive: true } }, methods: { onDragging(x, y) { this.x = x this.y = y }, onResizing(w, h) { this.w = w this.h = h } } } </script> <style> .content { width: 100%; height: 100%; background-color: #f0f0f0; border: 1px solid #ccc; border-radius: 4px; display: flex; align-items: center; justify-content: center; } </style> ``` 在这个示例中,我们使用了 vue-draggable-resizable 库来创建可元素。我们设置了元素的初始位置和大小,并监听了 dragging 和 resizing 事件来更新元素的状态。我们还根据元素的状态来动态更新了元素的样式和位置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值