Vue3实现拖拽改变元素大小

代码实现

整体页面结构通过一个 dragResize-wrapper 包含左右两个区域,左侧区域包含一个可拖拽的边界。以下是关键代码

HTML 部分
<template>
  <div class="dragResize-wrapper">
    <div class="dragResize-left">
      <div class="resize" @mousedown="resize"></div>
    </div>
    <div class="dragResize-right"></div>
  </div>
</template>
CSS 部分
<style lang="less" scoped>
.dragResize-wrapper {
  display: flex;
  width: 100vw;
  height: 100vh;
  .dragResize-left {
    position: relative;
    width: 30%;
    height: 100%;
    background-color: #1a2029;
    border-right: 1px solid #ccc;
    .resize {
      position: absolute;
      right: 0;
      width: 10px;
      height: 100%;
      background-color: #1a2029;
    }
    .resize:hover {
      cursor: e-resize;
    }
  }
  .dragResize-right {
    width: 70%;
    height: 100%;
    background-color: #472020;
  }
}
</style>
JavaScript 部分
<script setup>
import { ref, reactive, onMounted } from "vue";
const dragState = reactive({
  isDragging: false,
  startX: 0,
  leftInitialWidth: 0,
  minWidth: 100, // 左侧区域最小宽度限制
  maxWidth: 800, // 左侧区域最大宽度限制
});

const resize = (e) => {
  dragState.isDragging = true;
  dragState.startX = e.clientX; // 获取鼠标按下时的 X 坐标
  dragState.leftInitialWidth = e.currentTarget.parentElement.offsetWidth; // 获取左侧区域初始宽度
  document.body.style.cursor = "e-resize"; // 设置鼠标样式为拖拽样式
  document.body.style.userSelect = "none"; // 禁止选中文本
};

// 鼠标移动事件,执行拖拽调整宽度
const handleMouseMove = (e) => {
  if (!dragState.isDragging) return; // 如果没有拖拽,直接返回
  const deltax = e.clientX - dragState.startX; // 计算鼠标移动的距离
  let newWidth = dragState.leftInitialWidth + deltax; // 计算新的宽度
  newWidth = Math.max(
    dragState.minWidth,
    Math.min(newWidth, dragState.maxWidth)
  ); // 限制宽度在最小和最大值之间
  document.querySelector(".dragResize-left").style.width = `${newWidth}px`; // 设置左侧区域的新宽度
  document.querySelector(
    ".dragResize-right"
  ).style.width = `calc(100% - ${newWidth}px)`; // 设置右侧区域宽度为剩余空间
};

// 鼠标松开事件,结束拖拽
const handleMouseUp = () => {
  if (dragState.isDragging) {
    dragState.isDragging = false; // 重置拖拽状态
    document.body.style.cursor = "default"; // 恢复鼠标样式
    document.body.style.userSelect = "auto"; // 恢复文本选择
  }
};

onMounted(() => {
  document.addEventListener("mousemove", handleMouseMove); // 监听鼠标移动事件
  document.addEventListener("mouseup", handleMouseUp); // 监听鼠标松开事件
});
</script>

定义一个 dragState 对象来跟踪拖拽状态,包括是否正在拖拽、鼠标起始坐标、左侧区域初始宽度以及左右宽度限制。在 resize 函数中,设置拖拽开始时的相关状态和样式。handleMouseMove 函数根据鼠标移动距离计算新的宽度,并在一定范围内调整左右区域的宽度。handleMouseUp 函数用于结束拖拽并恢复样式。在组件挂载后添加鼠标移动和松开的事件监听。

完整实例代码

<template>
  <div class="dragResize-wrapper">
    <div class="dragResize-left">
      <div class="resize" @mousedown="resize"></div>
    </div>
    <div class="dragResize-right"></div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted } from "vue";
const dragState = reactive({
  isDragging: false,
  startX: 0,
  leftInitialWidth: 0,
  minWidth: 100, // 左侧区域最小宽度限制
  maxWidth: 800, // 左侧区域最大宽度限制
});

const resize = (e) => {
  dragState.isDragging = true;
  dragState.startX = e.clientX; // 获取鼠标按下时的X坐标
  dragState.leftInitialWidth = e.currentTarget.parentElement.offsetWidth; // 获取左侧区域初始宽度
  document.body.style.cursor = "e-resize"; // 设置鼠标样式为拖拽样式
  document.body.style.userSelect = "none"; // 禁止选中文本
};

// 鼠标移动事件,执行拖拽调整宽度
const handleMouseMove = (e) => {
  if (!dragState.isDragging) return; // 如果没有拖拽,直接返回
  const deltax = e.clientX - dragState.startX; // 计算鼠标移动的距离
  let newWidth = dragState.leftInitialWidth + deltax; // 计算新的宽度
  newWidth = Math.max(
    dragState.minWidth,
    Math.min(newWidth, dragState.maxWidth)
  ); // 限制宽度在最小和最大值之间
  document.querySelector(".dragResize-left").style.width = `${newWidth}px`; // 设置左侧区域的新宽度
  document.querySelector(
    ".dragResize-right"
  ).style.width = `calc(100% - ${newWidth}px)`; // 设置右侧区域宽度为剩余空间
};

// 鼠标松开事件,结束拖拽
const handleMouseUp = () => {
  if (dragState.isDragging) {
    dragState.isDragging = false; //重置拖拽状态
    document.body.style.cursor = "default"; // 恢复鼠标样式
    document.body.style.userSelect = "auto"; // 恢复文本选择
  }
};

onMounted(() => {
  document.addEventListener("mousemove", handleMouseMove); // 监听鼠标移动事件
  document.addEventListener("mouseup", handleMouseUp); // 监听鼠标松开事件
});
</script>

<style lang="less" scoped>
.dragResize-wrapper {
  display: flex;
  width: 100vw;
  height: 100vh;
  .dragResize-left {
    position: relative;
    width: 30%;
    height: 100%;
    background-color: #1a2029;
    border-right: 1px solid #ccc;
    .resize {
      position: absolute;
      right: 0;
      width: 10px;
      height: 100%;
      background-color: #1a2029;
    }
    .resize:hover {
      cursor: e-resize;
    }
  }
  .dragResize-right {
    width: 70%;
    height: 100%;
    background-color: #472020;
  }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值