Vue实现拖拽鼠标圈选、划区域、框选组件sgRectSelect:矩形区域选中checkbox,并回调相关选中、取消选中的操作

news2024/9/23 9:25:28

边框线虚线动画效果请参阅边框虚线滚动动画特效_虚线滚动效果_你挚爱的强哥的博客-CSDN博客【代码】边框虚线滚动动画特效。_虚线滚动效果https://blog.csdn.net/qq_37860634/article/details/130507289 

碰撞检测原理请前往 原生JS完成“一对一、一对多”矩形DIV碰撞检测、碰撞检查,通过计算接触面积(重叠覆盖面积)大小来判断接触对象DOM_js 碰撞检测_你挚爱的强哥的博客-CSDN博客这里就需要去遍历所有的target,计算每个重叠面积大小,挑出面积最大的那一个。stackArea=0代表没有重叠;stackArea >0代表有交集。为了方便计算比较,我们通常是在上面的代码基础上加一个面积大小判断,_js 碰撞检测https://blog.csdn.net/qq_37860634/article/details/121688431

还可以用此组件实现类似资源管理器的圈选效果

 


sgRectSelect框选组件源码  

<template>
    <div class="sgRectSelect" v-if="startPoint && endPoint" :style="style">
        <slot></slot>
    </div>
</template>
  
<script>
export default {
    data: () => ({
        startPoint: null,
        endPoint: null,
        style: {
            width: '0px',
            height: '0px',
            top: '0px',
            left: '0px',
        }
    }),
    props: [
        "data",//复杂对象
        /* data是一个数组格式:
        [
            {
                dom:文档对象,//必选
                index:'索引',
                id:'元素的id',
                refName:'ref别名',
                selectEvent:'选中后的操作',
                unSelectEvent:'取消选中后的操作',
            } ,
        ...
        ]
        */
        "selectDOMs",//只包含将可能被选中的DOM数组
        "borderWidth",
        "borderColor",
        "backgroundColor",
    ],
    mounted() { this.__addEvents(); },
    destroyed() { this.__removeEvents(); },
    methods: {
        __setProperty(dom) {
            if (!dom) return;
            dom.style.setProperty("--borderWidth", this.borderWidth || '1px');
            dom.style.setProperty("--borderColor", this.borderColor || '#409EFF');
            dom.style.setProperty("--backgroundColor", this.backgroundColor || '#409EFF22');
        },
        __addEvents() {
            this.__removeEvents();
            addEventListener('mousedown', this.mousedown);
            addEventListener('mousemove', this.mousemove);
            addEventListener('mouseup', this.mouseup);
        },
        __removeEvents() {
            removeEventListener('mousedown', this.mousedown);
            removeEventListener('mousemove', this.mousemove);
            removeEventListener('mouseup', this.mouseup);
        },
        mousedown(e) {
            this.startPoint = { x: e.clientX, y: e.clientY };
        },
        mousemove({ x, y }) {
            if (this.startPoint) {
                this.endPoint = { x, y };
                let width = this.endPoint.x - this.startPoint.x;
                let height = this.endPoint.y - this.startPoint.y;
                this.style = {
                    left: (width > 0 ? this.startPoint.x : this.endPoint.x) + 'px',
                    top: (height > 0 ? this.startPoint.y : this.endPoint.y) + 'px',
                    width: Math.abs(width) + 'px',
                    height: Math.abs(height) + 'px',
                }
                this.$nextTick(() => {
                    this.__setProperty(this.$el);
                    this.$emit('select', this.getSelectedDoms());
                });

            }
        },
        mouseup() {
            this.startPoint = null;
            this.endPoint = null;
        },
        // 获取被选中的DOM
        getSelectedDoms() {
            let r = [];
            if (this.data && this.data.length) {
                r = this.data.filter(v => {
                    let selected = this.isSelect(v.dom, this.$el);
                    (v.selectEvent && selected) && v.selectEvent(v);//执行被框选后的方法
                    (v.unSelectEvent && !selected) && v.unSelectEvent(v);//执行取消框选后的方法
                    return selected ? true : false;
                });
            } else {
                let doms = (this.selectDOMs && this.selectDOMs.length) ? this.selectDOMs : this.$parent.$el.querySelectorAll(`*`);
                r = [].slice.call(doms || []).filter(targetDom => this.isSelect(targetDom, this.$el));
            }
            // 获取被圈选的内容
            return r || [];
        },
        //判断多个矩形DIV是否重叠
        isSelect(targetDom, rectSelectDom) {
            if (targetDom === rectSelectDom) return false;
            let targetRect = targetDom.getBoundingClientRect();
            let selectRect = rectSelectDom.getBoundingClientRect();
            let tx1 = targetRect.left;
            let ty1 = targetRect.top;
            let tx2 = tx1 + targetRect.width;
            let ty2 = ty1 + targetRect.height;
            let mx1 = selectRect.left;
            let my1 = selectRect.top;
            let mx2 = mx1 + selectRect.width;
            let my2 = my1 + selectRect.height;
            let width = Math.min(tx2, mx2) - Math.max(tx1, mx1);
            let height = Math.min(ty2, my2) - Math.max(ty1, my1);
            let stackArea = (width > 0 ? width : 0) * (height > 0 ? height : 0);
            if (stackArea) return true;
            return false;
        },
    },
}
</script>
  
<style lang="scss" scoped>
.sgRectSelect {
    position: fixed;
    z-index: 1;
    box-sizing: border-box;
    border: var(--borderWidth) solid var(--borderColor);
    background-color: var(--backgroundColor);

    /*边框虚线滚动动画特效*/
    &[borderAnimate] {
        border: none;
        background: linear-gradient(90deg, var(--borderColor) 60%, transparent 60%) repeat-x left top/10px var(--borderWidth),
            linear-gradient(0deg, var(--borderColor) 60%, transparent 60%) repeat-y right top/var(--borderWidth) 10px,
            linear-gradient(90deg, var(--borderColor) 60%, transparent 60%) repeat-x right bottom/10px var(--borderWidth),
            linear-gradient(0deg, var(--borderColor) 60%, transparent 60%) repeat-y left bottom/var(--borderWidth) 10px, var(--backgroundColor);

        animation: border-animate .382s infinite linear;
    }

    @keyframes border-animate {
        0% {
            background-position: left top, right top, right bottom, left bottom;
        }

        100% {
            background-position: left 10px top, right top 10px, right 10px bottom, left bottom 10px;
        }
    }
}
</style>

应用组件 :

<template>
    <div class="sg-body">
        <sgRectSelect borderAnimate borderWidth="2px" borderColor="#F56C6C" backgroundColor="#F56C6C22"
            style="border-radius: 8px" @select="select" :data="data" />

        <el-checkbox-group v-model="checkboxGroupValue">
            <el-checkbox border :ref="`checkbox${i}`" v-for="(a, i) in checkboxs" :label="a.value" :key="i">{{ a.label
            }}</el-checkbox>
        </el-checkbox-group>
    </div>
</template>
    
<script>
import sgRectSelect from "@/vue/components/sgRectSelect";
export default {
    components: { sgRectSelect },
    data: () => ({
        data: [],
        checkboxGroupValue: [],
        checkboxs: [...Array(50)].map((v, i) => ({ label: '显示文本' + i, value: i }))
    }),
    mounted() {
        /* data是一个数组格式:
        [
            {
                dom:文档对象,//必选
                index:'索引',
                id:'元素的id',
                refName:'ref别名',
                selectEvent:'选中后的操作',
                unSelectEvent:'取消选中后的操作',
            } ,
        ...
        ]
        */
        this.data = [...Array(50)].map((v, i) => ({
            dom: this.$refs[`checkbox${i}`][0].$el,
            index: i,
            refName: `checkbox${i}`,
            /*  selectEvent: () => {
                 this.checkboxGroupValue = this.checkboxGroupValue.concat(i);
                 this.checkboxGroupValue = [...new Set(this.checkboxGroupValue)];
             },
             unSelectEvent: () => {
                 this.checkboxGroupValue = this.checkboxGroupValue.filter(v => v !== i);
             }, */
        }));
    },
    methods: {
        select(d) {
            this.checkboxGroupValue = [];
            d.forEach(v => {
                this.checkboxGroupValue = this.checkboxGroupValue.concat(v.index);
                this.checkboxGroupValue = [...new Set(this.checkboxGroupValue)];
            });
            console.log(`选中的对象`, d);
        },
    }
};
</script>
    
<style lang="scss" scoped>
.sg-body {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

车载以太网 - SomeIP - 协议用例 - RPC

目录 RPC Protocol specification 1、Cleint和Server端应该为一个服务实例的所有的Methodsevents使用一个TCP连接

AtCoder Regular Contest 163 C. Harmonic Mean(构造 补写法)

题目 t(t<500)组case&#xff0c; 给定一个数n(n<500)&#xff0c;构造一个长为n的数组 思路来源 官方题解 题解 注意到 ... 右边累加&#xff0c;等于1-最后一项&#xff0c;可以把最后一项挪到左边 所以&#xff0c; 1. 当n没有在前面的序列里出现过时&#xf…

centos7.6安装mysql

卸载mariadb 解决安装mysql与mariadb冲突问题&#xff08;卸载干净mariadb&#xff09;_何妨徐行的博客-CSDN博客 安装rpm包前可能需要的命令&#xff1a; yum install openssl-devel用于管理rpm包的工具 yum install lrzsz -y 文件传输缺乏rz 下载安装包 去mysql官网 把…

<Linux开发>驱动开发 -之- Linux I2C 驱动

&#xff1c;Linux开发&#xff1e;驱动开发 -之- Linux I2C 驱动 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详细…

[MMDetection]VOC数据格式转为COCO数据格式

以下脚本可以根据创建VOC格式数据集转换为COCO数据集 其中文件组织格式如下 VOC2007 ------Annotations ------***********.xml ------***********.xml -------ImageSets ------train.txt ------test.txt -------JPEGImages ------***********.jpg ------***********.jpg CO…

【Spring】SpringBoot参数验证10个技巧

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 前言 1.使用验证注解 2 使用自定义验证注解 3 在服务器端验证 4 提供有意义的错误信息 5 将 i18n 用于错误消息 6 使用分组验证 7 对复杂逻辑使用跨域验证 8 对验证错误使…

通过smtp发送邮件及执行异常解决

在日常中遇到了需要实现一个发送邮件的需求&#xff0c;完成之后记录下实现方法及自己遇到的一些问题及解决办法。 常用SMTP服务相关地址及端口 一、通过javax.mail实现发送邮件 1.引入相关坐标 <!-- 发送邮件--><dependency><groupId>org.projec…

矩阵系统源码智能回复私信场景开发

抖音矩阵系统源码智能回复私信场景开发 一、要想开发私信功能开发者需要准备的工作 开发者需要先对接官方api接口以及去申请api提交审核&#xff0c;目前需要了解官方对开发者对该能力开发权限的功能符合开发需求&#xff0c;其次需要了解官方私信触达的规则 1.申请流程&…

基于GPT构建单细胞多组学基础模型

生成式预训练模型在自然语言处理和计算机视觉等各个领域取得了显著的成功。特别是将大规模多样化的数据集与预训练的Transformer相结合&#xff0c;已经成为开发基础模型的一种有前途的方法。文本由单词组成&#xff0c;细胞可以通过基因进行表征。这种类比启发作者探索细胞和基…

Lingo优化软件初步

一、Lingo软件介绍 1、lingo软件的简单介绍 美国芝加哥大学的Linus Schrage教授于1980年左右开发的专门用于求解最优化问题的软件包&#xff0c;后经多年完善与扩充&#xff0c;并成立了LINDO系统公司进行商业运作取得巨大成功。根据 LINDO公司主页&#xff08;http://www.li…

分布式监控系统之zabbix6.0二

分布式监控系统之zabbix6.0二 一、部署 zabbix 代理服务器二、部署 Zabbix 高可用集群三、Zabbix 监控 Windows 系统四、Zabbix 监控 java 应用五、Zabbix 监控 SNMP 一、部署 zabbix 代理服务器 分布式监控的作用&#xff1a; 分担 server 的集中式压力解决多机房之间的网络…

暑假第4天打卡

Java: &#xff08;1&#xff09;标识符命名规范&#xff1a; > 包名&#xff1a;多单词组成时所有字母都小写&#xff1a;xxxyyyzzz。 例如&#xff1a;java.lang、com.atguigu.bean > 类名、接口名&#xff1a;多单词组成时&#xff0c;所有单词的首字母大写&#xf…

【一步到位】Jenkins的安装、部署、启动(完整教程)

一、测试环境 Linux系统 Centos 7 二、安装步骤&#xff1a; 1、安装jdk 我安装的是jdk8&#xff0c;此处就不多说了&#xff0c;自己百度哈&#xff0c;很简单 2、安装jenkins 首先依次执行如下三个命令&#xff1a; 2.1、导入镜像&#xff1a; [rootcentos7 ~]# sudo …

阿里P6跟P7有什么区别?

在互联网领域&#xff0c;阿里的职级和腾讯的职级体系相当于行业标准了&#xff0c;所以技术人还是需要学习一下/对标一下&#xff0c;从而知道自己目前在哪里&#xff0c;努力的方向是哪里&#xff1f;那么&#xff0c;阿里 P7 级别到底需要哪些能力呢&#xff1f;如下图思维导…

指针和数组笔试题解析

目录 数组笔试题 一维数组 字符数组 题 一 题 二 题 三 题 四 题 五 题 六 二维数组 指针笔试题 笔试题一 笔试题二 笔试题三 笔试题四 笔试题五 笔试题六 笔试题七 本篇博文&#xff0c;将从指针和数组来为大家分析一些笔试题&#xff0c;设计内…

IDEA+SpringBoot+mybatis+SSM+layui+Mysql客户管理系统源码

IDEASpringBootmybatisSSMlayuiMysql客户管理系统 一、系统介绍1.环境配置 二、系统展示1. 管理员登录2.修改密码3.客户管理4.添加客户5.充值记录管理6.消费记录管理7.客户类型8.添加客户类型 三、部分代码UserMapper.javaLoginController.javaUser.java 四、其他获取源码 一、…

【ElasticSearch】ES案例:旅游酒店搜索

文章目录 一、项目分析二、需求1&#xff1a;酒店搜索功能三、需求2&#xff1a;添加过滤功能四、需求3&#xff1a;我附近的酒店五、需求4&#xff1a;置顶花广告费的酒店 一、项目分析 启动hotel-demo项目&#xff0c;访问localhost:servicePort&#xff0c;即可访问static下…

不停服迭代更新-服务网格

系列文章目录 本章将根据多年经验&#xff0c;进行规划讲解 文章目录 系列文章目录前言一、如何做到 不停服更新、 不停服更新的机制有什么好处&#xff0c; 前言 服务迭代发版、少不了的就是停服更新&#xff0c;为了不影响 用户体验&#xff0c;大部分公司选择半夜更新迭代&…

TPCE260PCIE转PMC载板

TPCE60是一个标准的高度PCI Express版本1.1兼容的模块&#xff0c;提供了一个槽用于安装标准PMC模块&#xff0c;灵活和成本有效的I/O解决方案的各种应用如过程控制、医疗系统、电信和交通控制。 桥接PCI Express x1连接到主机板和PCI总线信号的PMC槽之间是由透明的PCIe到PCI桥…

正确释放vector的内存:clear还是swap?

一、size()和capacity()方法的区别 1、vector有size()和capacity()方法都用来获取vector的大小&#xff0c;那么它们两之间有什么区别呢&#xff1f; 我们先来看一段代码&#xff1a; int main() {std::vector<int> v1;std::cout <<"size:"<< v…