分屏拖动组件(PhScreenDrag)

  • Post author:
  • Post category:其他


技术栈:vue2



一、核心功能

支持拖动调节左右两侧盒子宽度



二、布局设计

  1. 采用 左-中-右 三列布局设计
  2. 左:左侧盒子显示内容
  3. 中:拖动竖线(鼠标悬浮时显示)
  4. 右:右侧盒子显示内容



三、组件参数

  1. 属性 Attributes
属性名 说明 类型 默认值
width 宽度,单位仅支持 px 、vw string ——
leftBoxWidth 左侧盒子默认宽度,单位仅支持 px 、vw string ——
max 最大阈值,即单个盒子最大宽度占比,最大值 1 number / string 0.8
disabled 是否禁用拖动 boolean false
haveDragSize 是否需要获取拖动距离 boolean false
  1. 插槽 Slots
名称 说明
leftContent 左侧盒子显示内容
rightContent 右侧盒子显示内容
  1. 方法 Events
方法名 说明
getDragSize 获取拖动距离,单位px;以初始化组件时竖线所在位置为原点,如拖动后竖线在原点左侧20px处,返回 -20px,在原点右侧20px处,则返回 20px,需配合haveDragSize使用



四、使用教程

  1. 引入并注册组件
<script>
import PhScreenDrag from '@/components/PhScreenDrag/Index'
export default {
  name: 'test',
  components: {
    PhScreenDrag
  }
}
</script>
  1. 使用
<template>
    <PhScreenDrag width="40vw" leftBoxWidth="20vw">
      <template slot="leftContent">
        <div>111111111111111111111111111111</div>
      </template>
      <template slot="rightContent">
        <div>222222222222222222222222222222</div>
      </template>
    </PhScreenDrag>
</template>

完整代码

<template>
  <div 
    id="drag-box" 
    class="drag-box" 
    :style="`width:${width}`"
  >
    <div 
      id="left-box" 
      class="drag-left-box" 
      :style="`width:${leftBoxWidth}`">
      <slot name="leftContent"></slot>
    </div>
    <div 
      id="drag-line"
      :class="`drag-line ${disabled ? 'drag-line_disabled' : ''}`" 
      @mousedown="handleMouseDown"
      @mouseup="handleMouseUp"
    >
      <div class="small-line"></div>
    </div>
    <div class="drag-right-box">
      <slot name="rightContent"></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'PhScreenDrag',
  props: {
    width: {
      type: String,
      default: ""
    }, // 宽度
    leftBoxWidth: {
      type: String,
      default: ""
    }, // 左侧盒子宽度
    max: {
      type: Number | String,
      default: 0.8
    }, // 最大阈值
    disabled: {
      type: Boolean,
      default: false
    }, // 是否禁用
    haveDragSize: {
      type: Boolean,
      default: false
    }, // 是否需要获取拖曳距离
  },
  data () {
    return {
      lineClientX: null, // 鼠标按下时竖线距离左侧屏幕的距离
      boxWidth: null, // 鼠标按下时左侧盒子宽度
    }
  },
  methods: {
    // 鼠标按下
    handleMouseDown (e) {
      if (this.disabled) return;
      this.lineClientX = e.clientX
      const width = document.getElementById("left-box").style.width
      const clentWidth = document.body.clientWidth;
      if (width.includes('px')) {
        this.boxWidth = width.replace(new RegExp("px"), "");
      } else {
        let vw = width.replace(new RegExp("vw"), "");
        this.boxWidth = (Number(clentWidth) / 100 * Number(vw)).toFixed(0)
      }
      document.addEventListener('mousemove', this.handleMouseMove,  { passive: false })
      document.addEventListener('mouseup', this.handleMouseUp,  { passive: false })
    },
    // 鼠标释放
    handleMouseUp () {
      document.removeEventListener('mousemove', this.handleMouseMove,  { passive: false })
      document.removeEventListener('mouseup', this.handleMouseUp,  { passive: false })
    },
    // 鼠标按下移动
    handleMouseMove (moveEvent) {
      if (!this.judgeMax(moveEvent)) return;
      // 左侧盒子宽度
      let boxDiv = document.getElementById("left-box")
      let moveDistance; // 移动距离
      if (moveEvent.clientX >= this.lineClientX) {
        moveDistance = Number(moveEvent.clientX) - Number(this.lineClientX);
        boxDiv.style.width = (Number(this.boxWidth) + moveDistance) + "px"
      } else {
        moveDistance = Number(this.lineClientX) - Number(moveEvent.clientX);
        boxDiv.style.width = (Number(this.boxWidth) - moveDistance) + "px"
      }
    },
    // 判断阈值
    judgeMax (e) {
      let canMove = true;
      // 分别判断盒子是否
      const clentWidth = document.body.clientWidth;
      let width = document.getElementById("drag-box").style.width
      if (width.includes('px')) {
        width = width.replace(new RegExp("px"), "");
      } else {
        let vw = width.replace(new RegExp("vw"), "");
        width = (Number(clentWidth) / 100 * Number(vw)).toFixed(0)
      }
      const leftBox = document.getElementById("left-box")
      let leftBoxWidth = leftBox.style.width
      if (leftBoxWidth.includes('px')) {
        leftBoxWidth = leftBoxWidth.replace(new RegExp("px"), "");
      } else {
        let vw = leftBoxWidth.replace(new RegExp("vw"), "");
        leftBoxWidth = (Number(clentWidth) / 100 * Number(vw)).toFixed(0)
      }
      const lineBox = document.getElementById("drag-line")
      // 拖动范围不能超过drag-box左边框及右边框
      if (this.max >= 1) {
        if ((e.clientX <= leftBox.getBoundingClientRect().left) ||
          ((Number(width) + Number(leftBox.getBoundingClientRect().left) - 5) <= e.clientX)) {
          canMove = false
        }
      } else {
        // 单个盒子阈值
        if ((Number(e.clientX) - Number(leftBox.getBoundingClientRect().left)) <= Number(width) * (1 - Number(this.max))){
          canMove = false
        }
        if ((Number(e.clientX) - Number(leftBox.getBoundingClientRect().left)) >= Number(width) * Number(this.max)) {
          canMove = false
        }
      }
      if (this.haveDragSize) {
        this.callBackDragSize(Number(e.clientX), Number(leftBox.getBoundingClientRect().left), clentWidth)
      }
      return canMove;
    },
    // 回调父组件拖动距离
    callBackDragSize (lineLeft, boxLeft, clentWidth) {
      let dragSize;
      let leftBoxWidth = this.leftBoxWidth;
      if (leftBoxWidth.includes('px')) {
        leftBoxWidth = leftBoxWidth.replace(new RegExp("px"), "");
      } else {
        let vw = leftBoxWidth.replace(new RegExp("vw"), "");
        leftBoxWidth = (Number(clentWidth) / 100 * Number(vw)).toFixed(0)
      }
      if ((lineLeft - boxLeft) > leftBoxWidth) {
        dragSize = (lineLeft - boxLeft - leftBoxWidth) + "px"
      } else {
        dragSize = '-' + (leftBoxWidth - (lineLeft - boxLeft)) + "px"
      }
      this.$emit("getDragSize", dragSize)
    }
  }
}
</script>
<style lang="scss" scoped>
.drag-box{
  display: flex;
  background: #fff;
  flex-wrap: wrap;
  .drag-left-box{
    overFlow: hidden;
    word-break: break-all;
  }
  .drag-line{
    width: 6px;
    cursor: col-resize;
    padding-left: 2px;
    .small-line{
      background: #fff;
      width: 2px;
      height: 100%;
      transition: background 0.2s;
    }
  }
  .drag-line:hover{
    .small-line{
      background: #409eff;
      transition: background 0.2s;
    }
  }
  .drag-line_disabled{
    cursor: not-allowed;
  }
  .drag-line_disabled:hover{
    background: #eee;
  }
  .drag-right-box{
    overFlow: hidden;
    word-break: break-all;
    flex: 1;
  }
}
</style>



版权声明:本文为qq_41775006原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。