自定义指令v-move移动元素到任意位置

所需效果如下:
请添加图片描述

代码如下:

<template>
  <div class="move-container">
    <div v-move:[params]="shuffle" :move-x="false" class="avatar">头像</div>
    <div v-move:[params2]="shuffle" class="nickname">昵称</div>
  </div>
</template>
<script>
  import { ref } from 'vue';
  export default {
    directives: {
      move: {
        mounted(el, binding) {
          const dragBox = el; //获取当前元素
          const boundary = binding.arg?.boundary ?? false; // 控制是否不能超出边界
          const callback =
            binding.value ??
            (() => {
              return null;
            });
          const canMoveX = el.getAttribute('move-x') !== false;
          const canMoveY = el.getAttribute('move-y') !== false;

          dragBox.style.position = 'absolute';
          const pdom = dragBox.parentNode;
          boundary && (pdom.style.position = 'relative');
          // 父元素宽高
          const pw = pdom.offsetWidth;
          const ph = pdom.offsetHeight;
          // 本身宽高
          const sw = dragBox.offsetWidth;
          const sh = dragBox.offsetHeight * 2; // 在控制父边界情况下避免元素超出范围
          // 计算得到最大移动距离
          const maxw = pw - sw + dragBox.offsetLeft;
          const maxh = ph - sh + dragBox.offsetHeight;
          const minw = 0;
          const minh = 0;

          dragBox.onmousedown = (e) => {
            // 阻止默认事件,避免元素选中
            e.preventDefault();
            dragBox.style.cursor = 'move';
            //算出鼠标当前相对元素的位置
            const disX = e.x - dragBox.offsetLeft;
            const disY = e.y - dragBox.offsetTop;

            document.onmousemove = (e2) => {
              //用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
              let left = e2.clientX - disX;
              let top = e2.clientY - disY;
              // 相对于父元素的移动百分比
              let percentX = 0;
              let percentY = 0;
              // 当传入true代表控制边界
              if (boundary) {
                left = left > maxw ? maxw : left < minw ? minw : left;
                top = top > maxh ? maxh : top < minh ? minh : top;
                // 计算移动百分比
                percentX = Number(((left / maxw) * 100).toFixed(2));
                percentY = Number(((top / maxh) * 100).toFixed(2));
              }

              //移动当前元素
              canMoveX && (dragBox.style.left = left + 'px');
              canMoveY && (dragBox.style.top = top + 'px');

              callback({ left, top, percentX, percentY }, binding.arg?.type);
            };
            document.onmouseup = () => {
              //鼠标弹起来的时候不再移动
              document.onmousemove = null;
              document.onmouseup = null;
              dragBox.style.cursor = 'default';
            };
          };
        },
      },
    },
    setup() {
      const boundary = ref(true);
      const type = ref('avatar');
      const params = {
        boundary: false,
        type: 'avatar',
      };
      const params2 = {
        boundary: true,
        type: 'nickname',
      };
      const shuffle = (e, type) => {
        console.log('e,', e);
        console.log('type,', type);
      };
      return {
        shuffle,
        boundary,
        type,
        params,
        params2,
      };
    },
  };
</script>
<style lang="less" scoped>
  .move-container {
    position: relative;
    width: 375px;
    height: 667px;
    margin-left: 100px;
    margin-top: 100px;
    background: #eee;

    .avatar {
      width: 38px;
      height: 38px;
      border: 1px solid red;
      background: pink;
      position: absolute;
    }

    .nickname {
      width: 48px;
      font-size: 24px;
      color: blue;
    }
  }
</style>

猜你喜欢

转载自blog.csdn.net/u013558749/article/details/125427412