vue3 + ts 通过自定义指令实现可以自由拖动的盒子

本文主要记录 vue3 自定义指令的用法的一个案例,通过自定义指令实现一个盒子(类似弹窗)可以被鼠标在浏览器的可视区域内自由拖动

下面直接上代码:(注:代码使用了 vue3 + ts 的写法) 

 template

<template>
  <div v-move class="max-box">
    <div class="header"></div>
    <div class="content">
      我是一个可以被鼠标拖动的盒子
    </div>
  </div>
</template>

typeScript

<script setup lang='ts'>
import { ref, Directive, DirectiveBinding } from 'vue';
// 定义一个自定义指令 v-move
const VMove: Directive<any, void> = (el: HTMLElement, bingding: DirectiveBinding) => {
  console.log('el', el);    // 这个 el 就是挂载 v-move 指定的元素
  // 获取到盒子右侧和底部可以移动到的最值
  const right = window.innerWidth - el.clientWidth
  const bottom = window.innerHeight - el.clientHeight
  console.log('盒子右下最值:', right, bottom);

  // 获取内部第一个div元素
  let moveElement: HTMLDivElement = el.firstElementChild as HTMLDivElement
  console.log('获取的元素', moveElement);   // 这里获取到的就是 header 所在的div元素

  // 鼠标按下的事件
  const mouseDown = (e: MouseEvent) => {
    let X = e.clientX - el.offsetLeft
    let Y = e.clientY - el.offsetTop
    // 鼠标移动事件
    const move = (e: MouseEvent) => {
      // 控制向左移动最左不能超出窗口左侧 且 向右移动最右不能让盒子超出窗口右侧
      let moveX = e.clientX - X < 0 ? 0 : ((e.clientX - X) > right ? right : e.clientX - X)
      // 控制向上移动最上不能超出窗口顶部 且 向下移动最下不能让盒子超出窗口底部
      let moveY = e.clientY - Y < 0 ? 0 : ((e.clientY - Y) > bottom ? bottom : e.clientY - Y)

      el.style.left = moveX + 'px'
      el.style.top = moveY + 'px'
    }
    document.addEventListener('mousemove', move)
    // 在鼠标抬起时去移除移动事件
    document.addEventListener('mouseup', () => {
      // 移除移动事件
      document.removeEventListener('mousemove', move)
    })
  }
  // 为获取到的div盒子绑定鼠标按下事件
  moveElement.addEventListener('mousedown', mouseDown)

}

</script>

style (less)

<style lang='less' scoped>
.max-box {
  width: 250px;
  min-height: 250px;
  background-color: #fff;
  position: absolute;
  top: 30%;
  left: 50%;

  .header {
    width: 100%;
    height: 30px;
    background-color: black;
    cursor: move;
  }

  .content {
    min-height: 250px;
    border: 2px solid black;
    border-top: 0;
    padding: 10px;
  }
}
</style>

效果图:

 特点:内部限制了盒子上下左右移动的范围最值,保证盒子只能在浏览器可视区域内移动。

猜你喜欢

转载自blog.csdn.net/qq_43551801/article/details/127758139