【sgDragMove】自定义组件:自定义拖拽组件,仅支持拖拽、设置吸附屏幕边界距离。

简介: 【sgDragMove】自定义组件:自定义拖拽组件,仅支持拖拽、设置吸附屏幕边界距离。


【sgDragMove】自定义拖拽组件,仅支持拖拽、设置吸附屏幕边界距离


特性:

  1. 支持拖拽元素与被拖拽元素可以分离
  2. 可自定义吸附边缘的距离,设置为0即可实现不超出界面停靠边界
  3. 拖拽过程,物体有半透明效果
  4. 拖拽的过程中可以通过disabled设置中断拖拽行为
  5. 吸附边缘的不同方向距离可以自定义,值可以是number或array类型,例如:是5代表[5,5,5,5],其中数组以此代表[上,右,下,左]
  6. 可以设置拖拽物体停靠距离边界的像素距离,值可以是number或array类型(规律同上)

sgDragMove源码

<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,//可以拖拽的位置元素数组or单个元素
                moveDom: elementDOM,//拖拽同步移动的元素数组or单个元素
            },
            ...
        ]
        */
        "disabled",//屏蔽
        "mousedownNearSide",//按下鼠标吸附边界
        "mousemoveNearSide",//移动鼠标吸附边界
        "mouseupNearSide",//弹起鼠标吸附边界
        "nearPadding",//距离边界多少像素自动吸附(mousedownNearSide||mousemoveNearSide||mouseupNearSide=true的时候才能生效),值可以是number或array类型,例如:是5代表[5,5,5,5],其中数组以此代表[上,右,下,左]
        "stopBoundary",//停靠边界距离,移动物体将按照这个值作为界限不再移出该范围(mousedownNearSide||mousemoveNearSide||mouseupNearSide=true的时候才能生效,值可以是number或array类型,例如:是5代表[5,5,5,5],其中数组以此代表[上,右,下,左]
        "cursor",//鼠标样式
        /*cursor格式说明:{
            grab:'default',//移入可拖拽区域的鼠标样式
            grabbing:'default',//拖拽过程中鼠标样式
        } */
    ],
    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();
    },
    mounted() {
        this.$parent.$el.style.setProperty("--sgDragMove-grab", (this.cursor || {}).grab || 'grab'); //js往css传递局部参数
        this.$parent.$el.style.setProperty("--sgDragMove-grabbing", (this.cursor || {}).grabbing || 'grabbing'); //js往css传递局部参数
    },
    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('sgDragMove_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('sgDragMove_grab', 'down');
            this.moveDom.setAttribute('sgDragMove_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();
        },
        setOffset(d) {
            this.offset = {
                ...this.offset,
                ...d
            };
        },
        mousemove_window(e) {
            this.canDragDom.setAttribute('sgDragMove_grab', 'down');
            this.moveDom.setAttribute('sgDragMove_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.style['transition-property'] = 'left,top';
            this.style['transition-duration'] = '0s,0s';
            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('sgDragMove_grab', 'ready');
            this.moveDom.setAttribute('sgDragMove_move', 'end');
            setTimeout(() => { this.moveDom && this.moveDom.removeAttribute('sgDragMove_move') }, 100);
            this.canDragDom = null;
            this.moveDom = null;
            this.__removeWindowEvents();
        },
        // 自动吸附网页边界
        nearSide() {
            let arr = this.nearPadding ? JSON.parse(JSON.stringify(this.nearPadding)) : 0; Array.isArray(arr) || (arr = [...Array(4)].map(v => arr));
            let [dis_top, dis_right, dis_bottom, dis_left] = arr;
            arr = this.stopBoundary ? JSON.parse(JSON.stringify(this.stopBoundary)) : 0; Array.isArray(arr) || (arr = [...Array(4)].map(v => arr));
            let [stopBoundary_top, stopBoundary_right, stopBoundary_bottom, stopBoundary_left] = arr;
            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_left, min_left = min_side_x + stopBoundary_left;
            let min_side_y = 0, min_y = min_side_y + dis_top, min_top = min_side_y + stopBoundary_top;
            x < min_x && (this.moveDom.style.left = `${min_left}px`);
            y < min_y && (this.moveDom.style.top = `${min_top}px`);
            let max_side_x = innerWidth - rect.width, max_x = max_side_x - dis_right, max_right = max_side_x - stopBoundary_right;
            let max_side_y = innerHeight - rect.height, max_y = max_side_y - dis_bottom, max_bottom = max_side_y - stopBoundary_bottom;
            x > max_x && (this.moveDom.style.left = `${max_right}px`);
            y > max_y && (this.moveDom.style.top = `${max_bottom}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">
[sgDragMove_grab="ready"] {
    cursor: var(--sgDragMove-grab); //css获取js传递的参数
    * {
        cursor: var(--sgDragMove-grab); //css获取js传递的参数
    }
    &:hover {
        opacity: 1;
    }
    &:active {
        opacity: 0.9;
    }
}
[sgDragMove_grab="down"] {
    cursor: var(--sgDragMove-grabbing); //css获取js传递的参数
    * {
        cursor: var(--sgDragMove-grabbing); //css获取js传递的参数
    }
}
[sgDragMove_move="ready"] {
    opacity: 1;
}
[sgDragMove_move="ing"] {
    opacity: 0.9;
}
[sgDragMove_move="end"] {
    transition: .1s;
}
</style>

应用

<sgDragMove
:data="dragMoveDoms"
nearPadding="50"
:disabled="traySize === 'lg'"
@dragStart="$emit(`dragStart`,
dragMoveDoms)"
@dragging="showRightBottomBtn = true;
$emit(`dragging`,
dragMoveDoms)"
@dragEnd="$emit(`dragEnd`,
dragMoveDoms)"
mouseupNearSide/>


相关文章
|
小程序
微信小程序如何实现进入小程序自动连WiFi功能
微信小程序如何实现进入小程序自动连WiFi功能
1043 0
|
JavaScript
Vue中 使用 moment.js 计算时间差值
Vue中 使用 moment.js 计算时间差值
1477 0
Vue中 使用 moment.js 计算时间差值
|
JavaScript 前端开发 Python
vue简单实现词云图组件
JavaScript也有许多可以用来生成词云图的库,但我自己其实都没有使用过,之前使用python的时候倒是用过python的wordcloud库,wordcloud库配合jieba库就可以很好的满足词频统计的需求,但在JavaScript这边我还没有了解很多词频统计这块的相关知识,在网上搜索了一番好像都没有搜索到有有关词频统计的相关库,而在词云生成这一方面的相关库倒是发现有不少,如:js2wordcloud、wordcloud2 等等……这些库都很好地实现了词云图片的展示,现在我也尝试着简单封装一个自己使用的简洁版词云图
1238 0
vue简单实现词云图组件
|
9月前
|
C#
C# 实现简单的 AOP(面向切面编程)
通过反射与委托实现AOP,可在方法执行前后动态添加日志、计时等横切逻辑,提升代码复用性与可维护性。
|
12月前
|
人工智能 前端开发 JavaScript
Ant Design X ✖️ 百宝箱智能体 SDK 极速构建 AI 聊天应用
本文介绍如何使用 Ant Design X 组件库与百宝箱 SDK 快速搭建 AI 对话应用。前端采用 React + Ant Design X,提供消息气泡、智能输入框等丰富组件;后端通过百宝箱 SDK 接入主流大模型,支持流式响应与高效数据管理,实现极简代码开发、快速上线的智能聊天应用。
1442 0
|
人工智能 运维 Prometheus
运维还要天天盯人值班?现代化运维就该让系统自己跑!
运维还要天天盯人值班?现代化运维就该让系统自己跑!
396 4
|
存储 网络协议 C#
C#实现与西门子S7-1200/1500 PLC通信
C#实现与西门子S7-1200/1500 PLC通信
|
编解码 前端开发 JavaScript
javascript检测网页缩放演示代码
javascript检测网页缩放演示代码
|
JavaScript 前端开发
【Vue 3】如何实现动态表单生成器的拖拽功能?
【Vue 3】如何实现动态表单生成器的拖拽功能?

热门文章

最新文章