手动实现鼠标拖动并动态添加div标签,添加的div可以自由拖拽大小

112 阅读1分钟

本例实现的功能有

  1. 鼠标拖动可动态添加div区域(可多次添加),
  2. 鼠标拖动div的两侧来调整div的大小
  3. 鼠标拖动div可左右移动div的位置
父组件
<template>
  <div class="wrap" id="wrap" ref="wrap"
  @mousedown="startDrag">
    <div id="drag" :style="{width: position.width + 'px', left: position.left + 'px'}" class="inner" v-show="isShow" />
    <div>
      <template v-for="(item, index ) in areaList">
        <drag1 @mousedown.native="editGrid(item, index)" :style="{width: item.position.width + 'px', left: item.position.left + 'px'}" class="inner" v-model="item.position" />
      </template>
    </div>
  </div>

</template>
<script setup>
import drag1 from './drag1.vue'
import { onMounted, reactive, ref, toRef, toRefs } from "vue";
let left = ref(0), width = ref(0), dragging = ref(false), areaList = reactive([])
let isShow = ref(true)
let position = reactive({})
let wrap = ref(null)
onMounted(() => {
  init()
})
function init() {
   let dom = wrap.value
  dom.addEventListener('mousedown', start)
}
function startDrag(){
  let dom = wrap.value
  dom.addEventListener('mousedown', start)
}
function editGrid(item, index) {
  let dom = wrap.value
    dom.removeEventListener('mousedown', start)
    document.removeEventListener('mousemove', drag)
    document.removeEventListener("mouseup", stopDrag);
}
function start(event) {
  dragging.value = true
  position.left = event.offsetX
  position.width = 0
  document.addEventListener("mousemove", drag);
  document.addEventListener("mouseup", stopDrag);
  isShow.value = true
}
function drag(event) {
    if(event.offsetX > 800) {
        position.width = 800 - position.left
    } else{
        position.width = event.offsetX - position.left
    }
}
function stopDrag() {
  document.removeEventListener('mousemove', drag)
  document.removeEventListener("mouseup", stopDrag);
  let result = toRefs(position)
  areaList.push({ position: { left: result.left.value, width: result.width.value } })
  isShow.value = false
}
</script>
<style scoped>
.wrap {
  position: relative;
  width: 800px;
  height: 100px;
  border: 1px solid #000;
  margin: 0 auto;
}
.inner {
  background: rgba(0, 0, 0, 0.2);
  height: 100%;
  position: absolute;
}
</style>
子组件
<template>
	<div class="resize" id="resize" ref="resize">
      <div class="left resize-handle" ref="left"></div>
      <div class="right resize-handle" ref="right"></div>
			<slot></slot>
    </div>
</template>
<script setup  lang="ts">
import { inject, onMounted, reactive, ref, unref, watch } from "vue";
let resize = ref(null);
let left = ref(null)
let right = ref(null)
let $emit = defineEmits(['update: modelValue'])
const model = defineModel()
let message = inject('value')
let props = defineProps(['fun'])
onMounted(() => {
	resize.value.style.width = model.value.width
	resize.value.style.left = model.value.left
  mousedown();  // 拖拽功能
  handleResize()
});

function mousedown() {
  resize.value.addEventListener("mousedown", startDrag);
}
// 拖拽功能
function startDrag(event) {
  let dragElement = resize.value
  event.preventDefault();
  const currentHandle = event.target;
  const isResizeHandle = currentHandle.className.includes("resize-handle");
  if (isResizeHandle) return;
  const startX = event.clientX;
  const startY = event.clientY;
  const startLeft = dragElement.offsetLeft;
  const startTop = dragElement.offsetTop;
  const width = dragElement.offsetWidth
  document.addEventListener("mousemove", drag);
  document.addEventListener("mouseup", stopDrag);
  let newLeft = startLeft
  function drag(event) {
    const dx = event.clientX - startX;
    const dy = event.clientY - startY;
    newLeft = startLeft + dx;
    const newTop = startTop + dy;
    dragElement.style.left = newLeft + "px";
    // dragElement.style.top = newTop + "px";
  }
  function stopDrag() {
    document.removeEventListener("mousemove", drag);
    document.removeEventListener("mouseup", stopDrag);
    // $emit('update: modelValue',{left: newLeft + 'px', width: width + 'px'})
		model.value = {left: newLeft+'px', width: width+'px'}
  }
}

// 缩放功能
function handleResize() {
  let domLeft = left.value
  let domRight = right.value
  domLeft.addEventListener('mousedown', (event:any) =>startResize(event,'left'))
  domRight.addEventListener('mousedown', (event:any) => startResize(event,'right'))
}
function startResize(event,type){
  event.preventDefault();
  let dragElement = resize.value
  const startX = event.clientX;
  const startWidth = dragElement.offsetWidth;
  const startLeft = dragElement.offsetLeft;
  document.addEventListener("mousemove", handleResize);
  document.addEventListener("mouseup", stopResize);
  var width, left
  function handleResize(event){
    const dx = event.clientX - startX;
    width = startWidth, left=startLeft
    if(type === 'left'){
      width = startWidth - dx;
      left = startLeft + dx;
    }
    if(type === 'right'){
      width = startWidth + dx;
      left = startLeft
    }
    dragElement.style.width = width + 'px';
    dragElement.style.left = left + 'px';
  }
  function stopResize(){
    if(width < 30) {
      return alert('宽度不能小于30像素')
    }
    document.removeEventListener("mousemove", handleResize);
    document.removeEventListener("mouseup", stopResize);
    model.value = {left: left+'px', width: width+'px'}
  }
}
</script>
<style scoped>
.resize {
  width: 120px;
  height: 200px;
  background: rgba(0, 0, 0, 0.2);
  position: absolute;
  top: 0;
}
.resize .left {
  position: absolute;
  height: 100%;
  border-left: 1px dashed #000;
  left: 0;
  width: 10px;
  cursor: pointer;
}
.resize .right {
  position: absolute;
  height: 100%;
  border-left: 1px dashed #000;
  right: -10px;
  width: 10px;
  cursor: pointer;
}
</style>