[sgDragMove] Custom drag and drop components, only support drag and drop, set the distance of the adsorption screen boundary

[sgDragMove] Custom drag and drop components, only support drag and drop, set the distance of the adsorption screen boundary


characteristic:

  1. Supports the separation of the dragged element and the dragged element
  2. You can customize the distance of the adsorption edge, set it to 0 so that it does not exceed the docking boundary of the interface
  3. During the dragging process, the object has a translucent effect
  4. During the dragging process, the dragging behavior can be interrupted by setting disabled

sgDragMove source code

<template>
    <div :class="$options.name"></div>
</template>
<script>
export default {
    name: 'sgDragMove',
    data: () => ({
        offset: { x: 0, y: 0, },//偏移量
        style: { top: '0px', left: '0px', },
        canDragDom: null,//触发拖拽事件的物体
        moveDom: null,//可以移动的物体
    }),
    props: [
        "data",//可以被拖拽的元素数组(必选) 
        /* data格式说明:
        [
            ...
            {
                canDragDom: elementDOM,//可以拖拽的位置元素
                moveDom: elementDOM,//拖拽同步移动的元素
            },
            ...
        ]
        */
        "disabled",//屏蔽
        "nearPadding",//距离边界多少像素自动吸附
        "mousedownNearSide",//按下鼠标吸附边界
        "mousemoveNearSide",//移动鼠标吸附边界
        "mouseupNearSide",//弹起鼠标吸附边界
    ],
    watch: {
        data: {
            handler(newValue, oldValue) {
                newValue ? this.__addDragsEvents(newValue) : this.__removeDragsEvents(oldValue);
            }, deep: true, immediate: true,
        },
        disabled: {
            handler(newValue, oldValue) {
                newValue ? this.__removeAllEvents() : this.__addAllEvents();
            }, deep: true, immediate: true,
        },
        style: {
            handler(newValue, oldValue) {
                if (this.moveDom && newValue && Object.keys(newValue).length) {
                    let d = newValue;
                    Object.keys(d).forEach(k => {
                        this.moveDom.style[k] = d[k]
                    });
                    this.moveDom.style.right = 'revert';
                    this.moveDom.style.bottom = 'revert';
                }
            },
            deep: true,//深度监听
            immediate: true,//立即执行
        },
    },
    destroyed() {
        this.__removeAllEvents();
    },
    methods: {
        __addAllEvents() {
            this.__addDragsEvents(this.data);
        },
        __removeAllEvents() {
            this.__removeWindowEvents();
            this.__removeDragsEvents(this.data);
        },
        __addWindowEvents() {
            this.__removeWindowEvents();
            addEventListener('mousemove', this.mousemove_window);
            addEventListener('mouseup', this.mouseup_window);
        },
        __removeWindowEvents() {
            removeEventListener('mousemove', this.mousemove_window);
            removeEventListener('mouseup', this.mouseup_window);
        },
        // 初始化需要拖拽的DIV
        __addDragsEvents(doms) {
            (doms || []).forEach(dom => {
                this.__removeDraggedEvents(dom.canDragDom);
                this.__addDraggedEvents(dom.canDragDom);
            });
        },
        __removeDragsEvents(doms) {
            (doms || []).forEach(dom => {
                this.__removeDraggedEvents(dom.canDragDom);
            });
        },
        __addDraggedEvents(dom) {
            dom.setAttribute('grab', 'ready');
            dom.addEventListener('dragstart', this.dragstart);
            dom.addEventListener('mousedown', this.mousedown);
        },
        __removeDraggedEvents(dom) {
            dom.removeEventListener('dragstart', this.dragstart);
            dom.removeEventListener('mousedown', this.mousedown);
        },
        dragstart(e) {
            e.stopPropagation(); e.preventDefault(); return false;
        },
        mousedown(e) {
            if (this.disabled) return this.mouseup_window(e);
            if (e.button === 2) return this.mouseup_window(e);//点击了鼠标右键
            this.canDragDom = e.currentTarget;
            this.moveDom = this.data.find(v => v.canDragDom == this.canDragDom).moveDom;
            this.canDragDom.setAttribute('grab', 'down');
            this.moveDom.setAttribute('move', 'ready');
            let or = this.moveDom.getBoundingClientRect();
            this.offset = { x: e.clientX - or.x, y: e.clientY - or.y, };
            (this.mousedownNearSide || this.mousedownNearSide === "") && this.nearSide();
            this.$emit('dragStart', this.getResult(e));
            this.__addWindowEvents();
        },
        mousemove_window(e) {
            if (this.disabled) return this.mouseup_window(e);
            this.canDragDom.setAttribute('grab', 'down');
            this.moveDom.setAttribute('move', 'ing');
            let x = e.clientX - this.offset.x;
            let y = e.clientY - this.offset.y;
            this.style = { left: x + 'px', top: y + 'px', };
            this.$nextTick(() => {
                (this.mousemoveNearSide || this.mousemoveNearSide === "") && this.nearSide();
                this.$emit('dragging', this.getResult(e));
            });
        },
        mouseup_window(e) {
            this.$emit('dragEnd', this.getResult(e));
            (this.mouseupNearSide || this.mouseupNearSide === "") && this.nearSide();
            this.offset = null;
            this.style = null;
            this.canDragDom.setAttribute('grab', 'ready');
            this.moveDom.setAttribute('move', 'end');
            this.canDragDom = null;
            this.moveDom = null;
            this.__removeWindowEvents();
        },     // 自动吸附网页边界
        nearSide() {
            if (typeof this.nearPadding !== 'undefined') {
                let dis = parseFloat(this.nearPadding);
                let x = parseFloat(this.moveDom.style.left);
                let y = parseFloat(this.moveDom.style.top);
                let rect = this.moveDom.getBoundingClientRect();

                let min_side_x = 0, min_x = min_side_x + dis;
                let min_side_y = 0, min_y = min_side_y + dis;
                x < min_x && (this.moveDom.style.left = min_side_x + 'px');
                y < min_y && (this.moveDom.style.top = min_side_y + 'px');

                let max_side_x = innerWidth - rect.width, max_x = max_side_x - dis;
                let max_side_y = innerHeight - rect.height, max_y = max_side_y - dis;
                x > max_x && (this.moveDom.style.left = max_side_x + 'px');
                y > max_y && (this.moveDom.style.top = max_side_y + 'px');
            }
        },
        getResult(e) {
            return {
                $event: e,
                canDragDom: this.canDragDom,
                moveDom: this.moveDom,
                canDragDomRect: this.canDragDom ? this.canDragDom.getBoundingClientRect() : null,
                moveDomRect: this.moveDom ? this.moveDom.getBoundingClientRect() : null,
            }
        },
    }
};
</script> 
<style lang="scss">
[grab="ready"] {
    cursor: grab;

    &:hover {
        opacity: 1;
    }

    &:active {
        opacity: 0.8;
    }
}

[grab="down"] {
    cursor: grabbing;
}

[move="ready"] {
    opacity: 1;
}

[move="ing"] {
    opacity: 0.8;
}

[move="end"] {
    transition: .8s cubic-bezier(.075, .82, .165, 1); //快速+柔和结束
}
</style>

Guess you like

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