vue 拖拽元素到任意位置

使用vue-drag-it-dude组件

npm install vue-drag-it-dude --save

参考地址:https://github.com/xzqyun/vue-drag-it-dude

import DragItDude from 'vue-drag-it-dude';

export default {
  name: '***',
  components: {
    DragItDude
  },
}

<template>
  <div id="app" class="parentElement">
    <drag-it-dude
      @activated="handleActivated"
      @dragging="handleDragging"
      @dropped="handleDropped"
    >
      <div class="innerElement">{{ text }}</div>
    </drag-it-dude>
  </div>
</template>

<script>
import DragItDude from "vue-drag-it-dude";

export default {
  name: "App",
  components: {
    DragItDude
  },
  data: () => ({
    text: "Just move me!",
  }),
  methods: {
    handleActivated() {
      this.text = "I am ready for great things!";
    },
    handleDragging() {
      this.text = "Weeee!";
    },
    handleDropped() {
      this.text = "That's place is awesome!";
      setTimeout(() => {
        this.text = "Just move me!";
      }, 3000);
    }
  }
};
</script>

<style>
  .parentElement {
    position: relative;
  }
</style>

由于该组件并没有返回元素的所在位置,所以我对该组件进行了稍微的改动

在components创建drag文件夹,放入DragItDude.vue,以下是DragItDude.vue的代码:

<template>
    <div class="drag-it-dude" @touchstart.stop="hang" @touchend.stop="drop" @mousedown.stop="hang" @mouseup.stop="drop"
     @touchmove.stop="iosMove" v-bind:style="{top:parentTop  + 'px',left:parentLeft + 'px'}">
        <slot></slot>
    </div>
</template>

<script>
    export default {
        name: 'drag',
        props: {
            width: {
                type: Number,
                default: 0,
            },
            height: {
                type: Number,
                default: 0,
            },
            parentWidth: {
                type: Number,
                default: 0,
            },
            parentHeight: {
                type: Number,
                default: 0,
            },
            parentLeft: {
                type: Number,
                default: 0,
            },
            parentTop: {
                type: Number,
                default: 0,
            },
        },
        watch: {
            width(newWidth, oldWidth) {
                if (newWidth < oldWidth) return;
                if (this.left === 0) return;

                this.parent.width = this.parentWidth || this.elem.parentNode.offsetWidth;
                this.parent.height = this.parentHeight || this.elem.parentNode.offsetHeight;

                if (newWidth > this.parent.width - this.left) {
                    const newLeft = this.parent.width - newWidth;
                    this.left = newLeft < 0 ? 0 : newLeft;
                    this.elem.style.left = `${this.left}px`;
                }
            },
            height(newHeight, oldHeight) {
                if (newHeight < oldHeight) return;
                if (this.top === 0) return;

                this.parent.width = this.parentWidth || this.elem.parentNode.offsetWidth;
                this.parent.height = this.parentHeight || this.elem.parentNode.offsetHeight;

                if (newHeight > this.parent.height - this.top) {
                    const newTop = this.parent.height - this.height;
                    this.top = newTop;
                    this.elem.style.top = `${this.top}px`;
                }
            },
        },
        data: () => ({
            shiftY: null,
            shiftX: null,
            left: 0,
            top: 0,
            elem: null,
            isIos: false,
            parent: {
                width: 0,
                height: 0,
            },
        }),
        methods: {
            iosMove(e) {
                if (this.isIos) this.elementMove(e);
            },
            elementMove(e) {
                this.$emit('dragging', {
                    left: this.left,
                    top: this.top
                });
                e.preventDefault();
                if (!e.pageX) {
                    document.body.style.overflow = 'hidden';
                }
                const x = e.pageX || e.changedTouches[0].pageX;
                const y = e.pageY || e.changedTouches[0].pageY;
                let newLeft = x - this.shiftX;
                let newTop = y - this.shiftY;
                const newRight = x - this.shiftX + this.elem.offsetWidth;
                const newBottom = y - this.shiftY + this.elem.offsetHeight;
                if (newLeft < 0) {
                    newLeft = 0;
                } else if (newRight > this.parent.width) {
                    newLeft = this.parent.width - this.elem.offsetWidth;
                } else {
                    newLeft = x - this.shiftX;
                }
                if (newTop < 0) {
                    newTop = 0;
                } else if (newBottom > this.parent.height) {
                    newTop = this.parent.height - this.elem.offsetHeight;
                } else {
                    newTop = y - this.shiftY;
                }
                this.elem.style.left = `${newLeft}px`;
                this.left = newLeft;
                this.elem.style.top = `${newTop}px`;
                this.top = newTop;
            },
            hang(e) {
                this.$emit('activated', {
                    left: this.left,
                    top: this.top
                });
                this.parent.width = this.parentWidth || this.elem.parentNode.offsetWidth;
                this.parent.height = this.parentHeight || this.elem.parentNode.offsetHeight;
                this.shiftX = e.pageX ?
                    e.pageX - this.elem.offsetLeft :
                    e.changedTouches[0].pageX - this.elem.offsetLeft;
                this.shiftY = e.pageY ?
                    e.pageY - this.elem.offsetTop :
                    e.changedTouches[0].pageY - this.elem.offsetTop;
                if (e.pageX) {
                    if (this.isIos) {
                        this.elem.addEventListener('touchmove', this.elementMove);
                    } else {
                        this.elem.addEventListener('mousemove', this.elementMove);
                        this.elem.addEventListener('mouseleave', this.drop);
                    }
                } else {
                    this.elem.addEventListener('touchmove', this.elementMove);
                }
            },
            drop() {
                this.$emit('dropped', {
                    left: this.left,
                    top: this.top
                });
                document.body.style.overflow = null;
                this.elem.removeEventListener('mousemove', this.elementMove, false);
                this.elem.removeEventListener('touchmove', this.elementMove, false);
                this.elem.onmouseup = null;
                this.elem.ontouchend = null;
            },
        },
        mounted() {
            this.isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
            this.elem = this.$el;
        },
    };
</script>

<style>
    .drag-it-dude {
        position: absolute;
        top: 0;
        left: 0;
        z-index: 1;
    }
</style>

引用:

import Drag from '../../../components/drag/DragItDude.vue';
export default {
        components: {
            Drag
          },

使用

<drag @dropped="handleDropped($event)" :parentTop="100" :parentLeft="100">
    <el-input></el-input>
</drag>

handleDropped(obj) {
    console.log(obj);//返回所在位置
},
Logo

前往低代码交流专区

更多推荐