vue2.0实现拖动div使得上下div高度变化

  <template>
    <div class="resizable-container">
      <!-- 上半部分内容区 -->
      <div 
        class="resizable-top"
        :style="{ height: topHeight + 'px' }"
      >
        上半部分内容(可拖动下方分隔线调整高度)
      </div>

      <!-- 拖动分隔线 -->
      <div 
        class="resizable-handle"
        @mousedown="startDrag"
        :style="{ cursor: dragStatus ? 'row-resize' : 'row-resize' }"
      ></div>

      <!-- 下半部分内容区 -->
      <div 
        class="resizable-bottom"
        :style="{ height: bottomHeight + 'px' }"
      >
        下半部分内容
      </div>
    </div>
  </template>

  <script>
  export default {
    name: "ResizableDiv",
    data() {
      return {
        // 容器总高度(可根据需求调整,也可动态获取父容器高度)
        containerHeight: 600,
        // 上半部分高度(初始值)
        topHeight: 300,
        // 下半部分高度(由总高度 - 上半部分高度 - 分隔线高度计算)
        bottomHeight: 298,
        // 拖动状态标记
        dragStatus: false,
        // 分隔线高度(固定)
        handleHeight: 4,
        // 上下部分最小高度限制
        minTopHeight: 100,
        minBottomHeight: 100
        startY:0,
        startTopHeight:0,
      };
    },
    mounted() {
      // 可选:动态获取父容器高度(替代固定 containerHeight)
      // this.containerHeight = this.$el.offsetHeight;
      // this.calcBottomHeight();

      // 监听全局鼠标移动和松开事件(避免拖动时鼠标移出分隔线失效)
      window.addEventListener("mousemove", this.onDrag);
      window.addEventListener("mouseup", this.endDrag);
      window.addEventListener("mouseleave", this.endDrag);
    },
    beforeDestroy() {
      // 移除全局事件监听(防止内存泄漏)
      window.removeEventListener("mousemove", this.onDrag);
      window.removeEventListener("mouseup", this.endDrag);
      window.removeEventListener("mouseleave", this.endDrag);
    },
    methods: {
      // 开始拖动:记录初始状态
      startDrag(e) {
        this.dragStatus = true;
        // 记录鼠标初始 Y 坐标(相对于容器顶部)
        this.startY = e.clientY - this.$el.getBoundingClientRect().top;
        // 记录拖动前的上半部分高度
        this.startTopHeight = this.topHeight;
        // 添加拖动时的全局样式(优化体验)
        document.body.style.userSelect = "none"; // 禁止文本选中
        document.body.style.cursor = "row-resize";
      },

      // 拖动中:计算高度变化
      onDrag(e) {
        if (!this.dragStatus) return;

        // 计算鼠标移动后的 Y 坐标(相对于容器顶部)
        const currentY = e.clientY - this.$el.getBoundingClientRect().top;
        // 计算上半部分高度变化值
        const diff = currentY - this.startY;
        let newTopHeight = this.startTopHeight + diff;

        // 边界控制:确保上半部分不小于最小高度,且下半部分也不小于最小高度
        const maxTopHeight = this.containerHeight - this.minBottomHeight - this.handleHeight;
        newTopHeight = Math.max(this.minTopHeight, Math.min(newTopHeight, maxTopHeight));

        // 更新上下部分高度
        this.topHeight = newTopHeight;
        this.calcBottomHeight();
      },

      // 结束拖动:重置状态
      endDrag() {
        this.dragStatus = false;
        // 恢复全局样式
        document.body.style.userSelect = "";
        document.body.style.cursor = "";
      },

      // 计算下半部分高度(总高度 - 上半部分高度 - 分隔线高度)
      calcBottomHeight() {
        this.bottomHeight = this.containerHeight - this.topHeight - this.handleHeight;
      }
    }
  };
  </script>

  <style scoped>
  .resizable-container {
    width: 100%;
    height: 100%; /* 可根据父容器调整,或使用固定高度 */
    max-height: 800px;
    border: 1px solid #e8e8e8;
    border-radius: 4px;
    overflow: hidden;
    position: relative;
  }

  /* 上半部分内容区 */
  .resizable-top {
    width: 100%;
    overflow: auto; /* 内容超出时滚动 */
    background: #fafafa;
    padding: 16px;
    box-sizing: border-box;
    transition: height 0.1s ease; /* 平滑过渡 */
  }

  /* 拖动分隔线 */
  .resizable-handle {
    width: 100%;
    height: 4px;
    background: #ddd;
    cursor: row-resize;
    transition: background 0.2s;
  }

  /* 拖动时分隔线样式优化 */
  .resizable-handle:hover,
  .resizable-handle:active {
    background: #1890ff; /* Element UI 主题色,可自定义 */
  }

  /* 下半部分内容区 */
  .resizable-bottom {
    width: 100%;
    overflow: auto; /* 内容超出时滚动 */
    background: #fff;
    padding: 16px;
    box-sizing: border-box;
    transition: height 0.1s ease; /* 平滑过渡 */
  }
  </style>
posted @ 2025-11-14 10:44  不完美的完美  阅读(11)  评论(0)    收藏  举报