[sgDrag_v2] [Independent research and development] Since the cloning element cycle generated by html2canvas is not fixed, dragstart, drag, and dragend are used to monitor drag events. The fly in the ointment is that there is a disabled mouse style

Look carefully at the above, dragging and dragging a forbidden mouse shape is disgusting~


sgDrag_v2.vue component source code

<template></template>
<script>
export default {
    name: 'sgDrag_v2',
    data() {
        return {
            timeout: null,
        }
    },
    props: [
        "data",//可以被拖拽的元素数组(必选)
        "targets",//需要被拖拽接触碰撞检测的元素(必选)
        "disabled",//屏蔽 
        "delay",//默认长按0.2秒 
    ],
    watch: {
        data: {
            handler(newValue, oldValue) {
                newValue ? this.__addDragsEvents(newValue) : this.__removeDragsEvents(oldValue);
            }, deep: true, immediate: true,
        },
        disabled: {
            handler(newValue, oldValue) {
                newValue ? this.__removeDragsEvents(this.data) : this.__addDragsEvents(this.data);
            }, deep: true, immediate: true,
        },
    },
    destroyed() {
        this.__removeDragsEvents(this.data);
    },
    methods: {
        // 初始化需要拖拽的DIV
        __addDragsEvents(doms) {
            (doms || []).forEach(dom => {
                this.__addMouseEvents(dom);
            });
        },
        __removeDragsEvents(doms) {
            (doms || []).forEach(dom => {
                this.__removeMouseEvents(dom);
                this.__removeDraggedEvents(dom);
            });
        },
        __addMouseEvents(dom) {
            this.__removeMouseEvents(dom);
            this.resetGrab(dom);
            dom.addEventListener('mousedown', this.mousedown);
            dom.addEventListener('mouseup', this.mouseup);
        },
        __removeMouseEvents(dom) {
            dom.setAttribute('draggable', false);
            this.resetGrab(dom);
            dom.removeEventListener('mousedown', this.mousedown);
            dom.removeEventListener('mouseup', this.mouseup);
        },
        __addDraggedEvents(dom) {
            this.__removeDraggedEvents(dom);
            dom.addEventListener('dragstart', this.dragstart);
            dom.addEventListener('drag', this.drag);
            dom.addEventListener('dragend', this.dragend);
        },
        __removeDraggedEvents(dom) {
            dom.removeEventListener('dragstart', this.dragstart);
            dom.removeEventListener('drag', this.drag);
            dom.removeEventListener('dragend', this.dragend);
        },
        mousedown(e) {
            if (this.disabled) return this.mouseup(e);
            // 长按delay毫秒开始监听拖拽(防止与其他单击事件冲突)
            let dom = e.currentTarget;
            this.timeout = setTimeout(() => {
                this.timeout = null;
                if (this.disabled) return;
                dom.setAttribute('draggable', true);
                dom.setAttribute('grab', 'down');
                this.$nextTick(() => {
                    this.dragstart(e);
                    this.__addDraggedEvents(dom);
                });
            }, typeof this.delay === 'undefined' ? 200 : this.delay);
        },
        mouseup(e) {
            if (this.disabled) return this.mouseup(e);
            this.resetGrab(e.currentTarget);
            if (this.timeout) {
                this.dragend(e);//放弃拖拽
                clearTimeout(this.timeout), (this.timeout = null);
            }
        },
        resetGrab(dom) {
            this.delay === 0 ? dom.setAttribute('grab', 'ready') : dom.removeAttribute('grab');
        },
        // 拖拽开始
        dragstart(e) {
            if (this.disabled) return this.mouseup(e);
            this.$emit(`dragStart`, this.getResult(e));
        },
        // 拖拽中
        drag(e) {
            if (this.disabled) return this.mouseup(e);
            this.$emit(`dragging`, this.getResult(e));
        },
        // 拖拽结束
        dragend(e) {
            if (this.disabled) return this.mouseup(e);
            let dom = e.currentTarget;
            dom.removeAttribute('draggable');
            this.resetGrab(dom);
            this.__removeDraggedEvents(dom);
            this.$emit(`dragEnd`, this.getResult(e));
        },
        getCrashDoms(e) {
            let targets = this.targets;
            targets['item'] && (targets = [].slice.call(targets));//NodeList对象
            Array.isArray(targets) || (targets = [targets]);//单个元素处理成数组
            return targets.filter(target => this.isMouseInTraget(target, e))
        },
        getResult(e) {
            return {
                $event: e,
                originDrag: e.currentTarget,
                originDragRect: e.currentTarget ? e.currentTarget.getBoundingClientRect() : null,
                crashDoms: this.getCrashDoms(e),
            }
        },
        //鼠标在元素内部
        isMouseInTraget(targetDom, mousePoint) {
            if (!mousePoint) return false;
            let tr = targetDom.getBoundingClientRect();
            let t = { x1: tr.x, x2: tr.x + tr.width, y1: tr.y, y2: tr.y + tr.height };//目标对象的四角顶点坐标
            let isIn =
                mousePoint.clientX >= t.x1 && mousePoint.clientX <= t.x2 &&
                mousePoint.clientY >= t.y1 && mousePoint.clientY <= t.y2;
            return isIn;
        },
    }
};
</script> 
<style lang="scss">
[grab="ready"] {
    cursor: grab !important;
}

[grab="down"] {
    cursor: grabbing !important;
}
</style>

application components

<template>
    <div class="sg-body">
        <sgDrag_v2 :data="data" :targets="targets" @dragStart="dragStart" @dragging="dragging" @dragEnd="dragEnd" />

        <div class=" drag-container">
            <div class="title">从此处拖拽出去</div>
            <div class="drag-div" :ref="`drag-div${i}`" v-for="(a, i) in items" :key="i" :index="i">{
   
   { a.label }}</div>
        </div>
        <div class="drag-in-container drag-container" ref="drag-in-container">
            <div class="title">放入此处</div>
            <div class="drag-div" :ref="`drag-div${i}`" v-for="(a, i) in dragInItems" :key="i" :index="i">{
   
   { a.label }}
            </div>
        </div>
    </div>
</template>
    
<script>
import sgDrag_v2 from "@/vue/components/sgDrag_v2";
export default {
    components: { sgDrag_v2 },
    data: () => ({
        data: [],//可以被拖拽的元素数组
        targets: [],//需要被拖拽接触碰撞检测的元素
        checkboxGroupValue: [],
        items: [...Array(20)].map((v, i) => ({ label: '显示文本' + i, value: i })),
        dragInItems: [],//动态拖拽进入的元素列表
    }),
    mounted() {
        this.data = [...Array(20)].map((v, i) => this.$refs[`drag-div${i}`][0]);
        this.targets = [this.$refs['drag-in-container']];
    },
    methods: {
        dragStart(d) {
            // console.log(`拖拽开始`, d);
        },
        dragging(d) {
            // console.log(`拖拽中`, d);
            let crashDoms = d.crashDoms;
            this.targets.forEach(dom => {
                crashDoms.includes(dom) ? dom.setAttribute('active', true) : dom.removeAttribute('active');
            });
        },
        dragEnd(d) {
            // console.log(`拖拽结束`, d);
            this.targets.forEach(dom => dom.removeAttribute('active'));
            // 如果翻下拖拽那一刻,正好在右侧区域内
            if (d.crashDoms.includes(this.targets[0])) {
                let index = parseInt(d.originDrag.getAttribute('index'));
                this.dragInItems.push(this.items.splice(index, 1)[0]);
            }
        },
    }
};
</script>
    
<style lang="scss" scoped>
.sg-body {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;

    .title {
        width: 100%;
        height: 50px;
        display: flex;
        justify-content: center;
        align-items: center;
        font-weight: bold;
        font-size: 18px;
    }

    .drag-div {
        width: 100px;
        height: 50px;
        background-color: #409EFF;
        margin: 2px;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .drag-container {
        width: 300px;
        height: 500px;
        overflow-y: auto;
        background-color: #00000011;
        display: flex;
        flex-wrap: wrap;
        align-content: flex-start;
    }

    .drag-in-container {
        background-color: #409EFF11;
        box-sizing: border-box;
        border: 1px dashed transparent;

        &[active] {
            border-color: #409EFF;
            background-color: #409EFF22;
        }
    }
}
</style>

sgDrag 1.0 version go here↓ 

[sgDrag] [Independent research and development] Vue-based development supports batch declaration of dragged elements and collided elements, monitors element collision detection during dragging and returns dragged original elements, cloned elements and their getBoundingClientRect objects and arrays of collided elements Array of objects and colliding contact elements . https://blog.csdn.net/qq_37860634/article/details/131645686

Guess you like

Origin blog.csdn.net/qq_37860634/article/details/131676350