【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/>


相关文章
|
定位技术
百度地图:监听地图缩放自动显示和隐藏的富文本标签
百度地图:监听地图缩放自动显示和隐藏的富文本标签
196 0
|
索引 容器
Bootstrap4----网络系统、图像形状、轮播、滚动监听、多媒体对象、下拉菜单导航及按钮
Bootstrap4----网络系统、图像形状、轮播、滚动监听、多媒体对象、下拉菜单导航及按钮
Qml实用技巧:在可视元素之前半透明覆盖一个可视元素,阻止鼠标透(界面)传(防止点击到被遮挡的按钮)
Qml实用技巧:在可视元素之前半透明覆盖一个可视元素,阻止鼠标透(界面)传(防止点击到被遮挡的按钮)
Qml实用技巧:在可视元素之前半透明覆盖一个可视元素,阻止鼠标透(界面)传(防止点击到被遮挡的按钮)
|
2月前
|
前端开发 JavaScript
原生撸移动端顶部滚动菜单栏,实现可滚动控制滚动边界动态样式
本文介绍了如何使用原生HTML、CSS和JavaScript创建一个移动端可滚动的顶部菜单栏。文章提供了详细的HTML结构、CSS样式和JavaScript代码,实现了菜单项的横向滚动、边界控制和动态样式变化。同时,还展示了如何通过触摸事件监听来控制菜单项的滚动和激活状态。
54 2
原生撸移动端顶部滚动菜单栏,实现可滚动控制滚动边界动态样式
|
3月前
|
前端开发 JavaScript
基于Vue3实现鼠标按下某个元素进行拖动,实时改变左侧或右侧元素的宽度,以及点击收起或展开的功能
本文介绍了如何在Vue3项目中实现一个鼠标拖动调整元素宽度的功能,并展示了点击按钮收起或展开侧边栏的效果,提供了完整的实现代码和操作演示。
655 0
基于Vue3实现鼠标按下某个元素进行拖动,实时改变左侧或右侧元素的宽度,以及点击收起或展开的功能
|
4月前
|
JavaScript
vue实战——元素的拖拽 + 控制元素无法拖拽出盒子 + 随元素拖拽自适应变化大小的盒子
vue实战——元素的拖拽 + 控制元素无法拖拽出盒子 + 随元素拖拽自适应变化大小的盒子
43 1
|
6月前
Echarts图表设置x轴y轴均随滚轮滚动缩+放 区域缩放
Echarts图表设置x轴y轴均随滚轮滚动缩+放 区域缩放
564 0
|
6月前
【sgSearch】自定义组件:常用搜索栏筛选框组件(包括表格高度变化兼容)。
【sgSearch】自定义组件:常用搜索栏筛选框组件(包括表格高度变化兼容)。
|
6月前
简单讲述ondragstart、drag、ondragend、ondragenter、ondragover、ondrop、ondragleave七个与拖拽相关的监听事件,并运用实现拖拽过程放置样式变化
简单讲述ondragstart、drag、ondragend、ondragenter、ondragover、ondrop、ondragleave七个与拖拽相关的监听事件,并运用实现拖拽过程放置样式变化
|
6月前
|
测试技术
【sgTileImage】自定义组件:瓦片图拖拽局部加载、实现以鼠标为中心缩放
【sgTileImage】自定义组件:瓦片图拖拽局部加载、实现以鼠标为中心缩放