实现简单的拖拽div改变宽与高封装组件

由于在需求过程中。需要实现一个页面的上下左右拖动效果。看到demo大部份是左右拖动。并且不是完全的封装。都因此在前人的代码基础上去实现一个vue2的拖动布局组件,通过插槽无缝嵌入

实现效果如下

布局逻辑

  • 使用<div>元素创建了一个名为dragBox的容器,它包含三个主要部分:左侧面板(dragBox-left)、拖动条(drag)和右侧面板(dragBox-right)。
  • 通过slot标签提供了插槽,允许用户自定义左右面板的内容。
js 复制代码
<template>
  <div ref="dragBox" class="dragBox" :class="dragBoxClass">
    <div class="dragBox-left" ref="dragBox_left">
      <slot name="left"></slot>
    </div>
    <div ref="drag" class="drag" :class="dragClass">
      <span v-for="item in 3" :key="item"></span>
    </div>
    <div class="dragBox-right" ref="dragBox_right">
      <slot name="right"></slot>
    </div>
  </div>
</template>
    
    

拖动逻辑思路

  • 鼠标按下事件 (mousedown) :当用户按下鼠标时,记录当前鼠标位置并开始拖动。

  • 鼠标移动事件 (mousemove) :当用户拖动鼠标时,根据鼠标的移动距离调整对应的区域大小。

  • 鼠标松开事件 (mouseup) :当用户松开鼠标时,停止拖动并清理事件。

1. 鼠标按下事件 (mousedown)

当用户按下拖动控件时,我们需要记录鼠标的初始位置,并设置拖动控件的初始偏移位置。以下是纵向拖动的实现代码:

js 复制代码
dragControllerUpDown() {
  let resize = this.$refs.drag;
  let left = this.$refs.dragBox_left;
  let right = this.$refs.dragBox_right;
  let box = this.$refs.dragBox;
  
  resize.onmousedown = function (e) {
    // 改变拖动控件的颜色提示用户正在拖动
    resize.style.background = '#818181';
    
    // 记录鼠标的初始位置
    let startY = e.clientY;
    // 记录拖动控件的初始偏移位置
    resize.top = resize.offsetTop;
    
    // 鼠标拖动事件
    document.onmousemove = function (e) {
      // 计算鼠标移动的距离
      let endY = e.clientY;
      let moveLen = resize.top + (endY - startY);
      
      // 获取容器的最大高度,防止拖动超出范围
      let maxT = box.clientHeight - resize.offsetHeight;
      if (moveLen < 200) moveLen = 200; // 设置上边区域的最小高度
      if (moveLen > maxT - 200) moveLen = maxT - 200; // 设置下边区域的最小高度
      
      // 更新拖动控件和左右区域的高度
      resize.style.top = moveLen;
      left.style.height = moveLen + 'px';
      right.style.height = box.clientHeight - moveLen - 10 + 'px';
    };
    
    // 鼠标松开事件
    document.onmouseup = function () {
      // 恢复拖动控件的颜色
      resize.style.background = '#d6d6d6';
      // 移除鼠标移动和松开事件
      document.onmousemove = null;
      document.onmouseup = null;
      // 释放鼠标捕获
      resize.releaseCapture && resize.releaseCapture();
    };
    
    // 捕获鼠标事件
    resize.setCapture && resize.setCapture();
    return false;
  };
}

2. 鼠标移动事件 (mousemove)

mousemove 事件中,我们根据鼠标的移动距离来调整左右或上下区域的大小。以下是详细的逻辑解释:

  • 计算鼠标移动的距离endY - startY 计算出鼠标移动的距离。
  • 计算新的控件位置resize.top + (endY - startY) 计算出拖动控件的新位置。
  • 防止超出边界:通过设置最小和最大高度/宽度,防止拖动超出容器的边界。
  • 更新高度/宽度:根据新的控件位置,更新左右或上下区域的高度/宽度。

3. 鼠标松开事件 (mouseup)

mouseup 事件中,我们需要停止拖动并清理事件,具体步骤如下:

  • 恢复拖动控件的颜色:提示用户拖动已结束。
  • 移除 mousemovemouseup 事件:停止拖动逻辑。
  • 释放鼠标捕获:使得控件不再捕获鼠标事件。

横向拖动逻辑

横向拖动逻辑与纵向类似,只是坐标从 Y 轴改为 X 轴,高度改为宽度:

添加监听事件window的resize事件。实时获取盒子的宽或高

js 复制代码
  window.addEventListener('resize', this.GetDragscreen);
  
   GetDragscreen() {
      //获取当前dragBox的高度或宽度(根据你当前的type来决定)
      if (this.DragType == 'column') {
        return this.$refs.dragBox.clientHeight;
      } else if (this.DragType == 'row') {
        return this.$refs.dragBox.clientWidth;
      }
    },

完整代码

js 复制代码
<template>
  <div ref="dragBox" class="dragBox" :class="dragBoxClass">
    <div class="dragBox-left" ref="dragBox_left">
      <slot name="left"></slot>
    </div>
    <div ref="drag" class="drag" :class="dragClass">
      <span v-for="item in 3" :key="item"></span>
    </div>
    <div class="dragBox-right" ref="dragBox_right">
      <slot name="right"></slot>
    </div>
  </div>
</template>
<script>
export default {
  name: 'drag',
  props: {
    DragType: {
      type: String,
      default: 'column',
    },
  },
  computed: {
    dragBoxClass() {
      return {
        DragUpDown: this.DragType === 'column',
        DragLeftRight: this.DragType === 'row',
      };
    },
    dragClass() {
      return {
        'DragLeftRight-drag': this.DragType === 'row',
        'DragUpDown-drag': this.DragType === 'column',
      };
    },
  },
  data() {
    return {
      screenWidth: 0, // 获取当前dragBox的宽度或高度
    };
  },
  mounted() {
    this.GetDragscreen();
    this.dragControllerDiv();
    window.addEventListener('resize', this.GetDragscreen);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.GetDragscreen);
  },
  watch: {
    screenWidth(newVal, oldVal) {
      this.DragType == 'column' && this.watchDragUpDown(newVal);

      this.DragType == 'row' && this.watchDragLeftRight(newVal);
    },
  },
  methods: {
    watchDragUpDown(newVal) {
      //在拖动中一直更改右边的高度
      let resize = this.$refs.drag;
      let right = this.$refs.dragBox_right;
      right.style.height = newVal - resize.offsetTop + 'px';
    },
    watchDragLeftRight(newVal) {
      //在拖动中一直更改div的高度
      let resize = this.$refs.drag;
      let right = this.$refs.dragBox_right;
      right.style.width = newVal - resize.offsetLeft + 'px';
    },
    setDragscreen() {
      //设置当前dragBox的高度或宽度(根据你当前的type来决定)
      if (this.DragType == 'column') {
        this.screenWidth = this.$refs.dragBox.clientHeight;
      } else if (this.DragType == 'row') {
        this.screenWidth = this.$refs.dragBox.clientWidth;
      }
    },
    GetDragscreen() {
      //获取当前dragBox的高度或宽度(根据你当前的type来决定)
      if (this.DragType == 'column') {
        return this.$refs.dragBox.clientHeight;
      } else if (this.DragType == 'row') {
        return this.$refs.dragBox.clientWidth;
      }
    },

    dragControllerDiv() {
      this.DragType == 'column' && this.dragControllerUpDown();
      this.DragType == 'row' && this.dragControllerLeftRight();
    },

    dragControllerUpDown() {
      let resize = this.$refs.drag;
      let left = this.$refs.dragBox_left;
      let right = this.$refs.dragBox_right;
      let box = this.$refs.dragBox;
      // 鼠标按下事件
      resize.onmousedown = function (e) {
        //颜色改变提醒
        resize.style.background = '#818181';
        let startX = e.clientY;
        resize.top = resize.offsetTop;
        // 鼠标拖动事件
        document.onmousemove = function (e) {
          let endX = e.clientY;
          let moveLen = resize.top + (endX - startX); // (endx-startx)=移动的上下距离。
          //resize.left+移动的距离=左边区域最后的宽度
          let maxT = box.clientHeight - resize.offsetHeight; // 容器高度 - 左边区域的宽度 = 右边区域的宽度
          if (moveLen < 200) moveLen = 200; // 上边区域的最小高度为200
          if (moveLen > maxT - 200) moveLen = maxT - 200; //右边区域最小高度为200
          resize.style.top = moveLen; // 设置上边区域的宽度
          left.style.height = moveLen + 'px';
          right.style.height = box.clientHeight - moveLen - 10 + 'px';
        };
        // 鼠标松开事件
        document.onmouseup = function (evt) {
          //颜色恢复
          resize.style.background = '#d6d6d6';
          document.onmousemove = null;
          document.onmouseup = null;
          resize.releaseCapture && resize.releaseCapture(); //当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉
        };
        resize.setCapture && resize.setCapture(); //该函数在属于当前线程的指定窗口里设置鼠标捕获
        return false;
      };
    },
    dragControllerLeftRight() {
      let resize = this.$refs.drag;
      let left = this.$refs.dragBox_left;
      let right = this.$refs.dragBox_right;
      let box = this.$refs.dragBox;
      // 鼠标按下事件
      resize.onmousedown = function (e) {
        //颜色改变提醒
        resize.style.background = '#818181';
        let startX = e.clientX;
        resize.left = resize.offsetLeft;
        // 鼠标拖动事件
        document.onmousemove = function (e) {
          let endX = e.clientX;
          let moveLen = resize.left + (endX - startX); // (endx-startx)=移动的左右距离。
          //resize.left+移动的距离=左边区域最后的宽度
          let maxT = box.clientWidth - resize.offsetWidth; // 容器宽度 - 左边区域的宽度 = 右边区域的宽度
          if (moveLen < 200) moveLen = 200; // 左边区域的最小宽度为200
          if (moveLen > maxT - 200) moveLen = maxT - 200; //右边区域最小宽度为200
          resize.style.left = moveLen; // 设置左侧区域的宽度

          left.style.width = moveLen + 'px';
          right.style.width = box.clientWidth - moveLen - 10 + 'px';
        };
        // 鼠标松开事件
        document.onmouseup = function (evt) {
          //颜色恢复
          resize.style.background = '#d6d6d6';
          document.onmousemove = null;
          document.onmouseup = null;
          resize.releaseCapture && resize.releaseCapture(); //当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉
        };
        resize.setCapture && resize.setCapture(); //该函数在属于当前线程的指定窗口里设置鼠标捕获
        return false;
      };
    },

    beforeDestroy() {
      window.onresize = null;
    },
  },
};
</script>
<style lang="less" scoped>
/*拖拽区div样式*/
.DragLeftRight-drag {
  margin: 10px;
  width: 10px;
  height: 50px;
  top: calc(50% - 25px);
  font-size: 32px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  > span {
    margin-top: 3px;
    margin-bottom: 3px;
  }
}
.DragUpDown-drag {
  width: 50px;
  height: 10px;
  left: calc(50% - 40px);
  margin: 10px;
  align-items: center;
  justify-content: center;
  > span {
    margin-left: 3px;
    margin-right: 3px;
  }
}
.drag {
  display: flex;
  border-radius: 5px;
  cursor: col-resize;
  position: relative;
  background-color: #d6d6d6;
  background-size: cover;
  background-position: center;
  > span {
    width: 5px;
    height: 5px;
    display: block;
    background: #fff;
    border-radius: 50%;
  }
}
/*拖拽区鼠标悬停样式*/
.drag:hover {
  color: #444444;
}
.dragBox {
  display: flex;
  width: 100%;
  height: 100%;
}
.DragUpDown {
  flex-direction: column;
  > .dragBox-left,
  > .dragBox-right {
    width: 100%;
    height: 50%;
    overflow: hidden;
  }
}
.DragLeftRight {
  flex-direction: row;
  > .dragBox-left,
  > .dragBox-right {
    width: 50%;
    height: 100%;
    overflow: hidden;
  }
}
</style>
    ```
相关推荐
汪子熙17 分钟前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
Envyᥫᩣ25 分钟前
《ASP.NET Web Forms 实现视频点赞功能的完整示例》
前端·asp.net·音视频·视频点赞
Мартин.4 小时前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
昨天;明天。今天。6 小时前
案例-表白墙简单实现
前端·javascript·css
数云界6 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
风清扬_jd6 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常6 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
ChinaDragonDreamer6 小时前
Vite:为什么选 Vite
前端
小御姐@stella6 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing6 小时前
【React】增量传输与渲染
前端·javascript·面试