vue实现穿梭框,ctrl多选,shift多选

news2025/1/16 16:50:40

效果图

 代码

<template>
    <div class="container">
        <!--左侧-->
        <div>
            <div class="title">{{ titles[0] }}</div>
            <div class="layerContainer">
                <div v-for="item in leftLayerArray"
                     :key="getKey(item)"
                     :ref="getRefKey(item)"
                     @click="e =>layerClicked(e,item,true)"
                >
                    <el-tooltip effect="light" :content="item.key" placement="top" v-if="item.key.length > 10">
                        <div>{{ item.key }}</div>
                    </el-tooltip>
                    <div v-else>{{ item.key }}</div>
                </div>
            </div>
        </div>
        <!--中间按钮-->
        <div class="centerButton">
            <div @click="transferToRight">&gt;</div>
            <div @click="transferAllToRight">&gt;&gt;</div>
            <div @click="transferToLeft">&lt;</div>
            <div @click="transferAllToLeft">&lt;&lt;</div>
        </div>
        <!--右侧-->
        <div>
            <div class="title">{{ titles[1] }}</div>
            <div class="layerContainer">
                <div v-for="item in rightLayerArray"
                     :key="getKetRight(item)"
                     :ref="getRefKeyRight(item)"
                     @click="e =>layerClicked(e,item, false)"
                >
                    <el-tooltip effect="light" :content="item.key" placement="top" v-if="item.key.length > 10">
                        <div>{{ item.key }}</div>
                    </el-tooltip>
                    <div v-else>{{ item.key }}</div>
                </div>
            </div>
        </div>
        <!--  上下移动的按钮  -->
        <div class="transfer-right-buttons">
            <div :class="upClass" @click="moveMoreStep('up')">
                <img src="图片地址"
                     alt="">
            </div>
            <div :class="upClass" @click="moveOneStep('up')">
                <img src="图片地址"
                     alt="">
            </div>
            <div :class="downClass" @click="moveOneStep('down')">
                <img src="图片地址"
                     alt="">
            </div>
            <div :class="downClass" @click="moveMoreStep('down')">
                <img src="图片地址"
                     alt="">
            </div>
        </div>
    </div>
</template>
<script>

export default {
    name: "ha-transfer",
    props: {
        titles: {
            type: Array,
            default: () => ['地图图层', '图例项']
        },
        originData: {
            type: Array,
            default: () => [
                {
                    key: '点图层',
                    id: 1
                },
                {
                    key: '线图层',
                    id: 2
                },
                {
                    key: '面图层',
                    id: 3
                },
                {
                    key: '多点图层',
                    id: 4
                },
                {
                    key: '多线图层',
                    id: 5
                },
                {
                    key: '多面图层',
                    id: 6
                }
            ]
        },
        selectedData: {
            type: Array,
            default: () => [
                {
                    key: '图例项1',
                    id: 7
                },
                {
                    key: '图例项2',
                    id: 8
                },
                {
                    key: '图例项3',
                    id: 9
                },
                {
                    key: '图例项4',
                    id: 10
                },
                {
                    key: '图例项5',
                    id: 11
                },
                {
                    key: '图例项6',
                    id: 12
                }
            ]
        }
    },
    data() {
        return {
            leftLayerArray: [...this.originData],
            leftCurrentSelectedLayer: [],
            rightLayerArray: [...this.selectedData],
            rightCurrentSelectedLayer: []
        }
    },
    computed: {
        upClass() {
            if (this.rightCurrentSelectedLayer.length === 0) {
                return 'disabled'
            }
            for (let item of this.rightCurrentSelectedLayer) {
                if (item.id === this.rightLayerArray[0].id) {
                    return 'disabled'
                }
            }
            return ''
        },

        downClass() {
            if (this.rightCurrentSelectedLayer.length === 0) {
                return 'disabled'
            }
            for (let item of this.rightCurrentSelectedLayer) {
                if (item.id === this.rightLayerArray[this.rightLayerArray.length - 1].id) {
                    return 'disabled'
                }
            }
            return ''
        },
    },
    methods: {
        getRefKey(item) {
            return `layer-${item.id}`
        },
        getKey(item) {
            return `layer-${item.id}`
        },
        getRefKeyRight(item) {
            return `layer-right-${item.id}`
        },
        getKetRight(item) {
            return `layer-right-${item.id}`
        },

        /**
         * 单击穿梭框列表项,选中或取消选中
         * @param e 事件对象
         * @param item  当前项
         * @param isLeft  是否是左侧
         */
        layerClicked(e, item, isLeft) {
            let currentLayer, layerArray, refFunction
            if (isLeft) {
                currentLayer = [...this.leftCurrentSelectedLayer]
                layerArray = [...this.leftLayerArray]
                refFunction = this.getRefKey
            } else {
                currentLayer = [...this.rightCurrentSelectedLayer]
                layerArray = [...this.rightLayerArray]
                refFunction = this.getRefKeyRight
            }

            const refElement = this.$refs[refFunction(item)][0];

            if (e.ctrlKey || e.metaKey) {
                const isSelected = currentLayer.includes(item);
                if (isSelected) {
                    refElement.classList.remove('active');
                    currentLayer.splice(currentLayer.indexOf(item), 1);
                } else {
                    refElement.classList.add('active');
                    currentLayer.push(item);
                }
            } else if (e.shiftKey) {
                const firstIndex = layerArray.indexOf(currentLayer[0]);
                const lastIndex = layerArray.indexOf(item);
                const [startIndex, endIndex] = [firstIndex, lastIndex].sort();

                currentLayer = layerArray.slice(startIndex, endIndex + 1);

                layerArray.forEach((item, index) => {
                    const refElement = this.$refs[refFunction(item)][0];
                    if (index >= startIndex && index <= endIndex) {
                        refElement.classList.add('active');
                    } else {
                        refElement.classList.remove('active');
                    }
                })
            } else {
                currentLayer = [item];
                layerArray.forEach(item => {
                    this.$refs[refFunction(item)][0].classList.remove('active');
                })
                refElement.classList.add('active');
            }
            if (isLeft) {
                this.leftCurrentSelectedLayer = [...currentLayer];
                this.leftLayerArray = [...layerArray];
            } else {
                this.rightCurrentSelectedLayer = [...currentLayer];
                this.rightLayerArray = [...layerArray];
            }
        },

        /**
         * 把选中的图层移动到右侧
         */
        transferToRight() {
            this.rightLayerArray.push(...this.leftCurrentSelectedLayer)
            this.leftLayerArray = this.leftLayerArray.filter(item => {
                return this.leftCurrentSelectedLayer.indexOf(item) === -1
            })
            this.leftCurrentSelectedLayer = []
        },
        /**
         * 把所有的图层移动到右侧
         */
        transferAllToRight() {
            this.rightLayerArray.push(...this.leftLayerArray)
            this.leftCurrentSelectedLayer = []
            this.leftLayerArray = []
        },

        /**
         * 把选中的图层移动到左侧
         */
        transferToLeft() {
            this.leftLayerArray.push(...this.rightCurrentSelectedLayer)
            this.rightLayerArray = this.rightLayerArray.filter(item => {
                return this.rightCurrentSelectedLayer.indexOf(item) === -1
            })
            this.rightCurrentSelectedLayer = []
        },
        /**
         * 把所有的图层移动到左侧
         */
        transferAllToLeft() {
            this.leftLayerArray.push(...this.rightLayerArray)
            this.rightCurrentSelectedLayer = []
            this.rightLayerArray = []
        },

        /**
         * 向上或向下移动一步
         * @param status
         */
        moveOneStep(status) {
            if (status === 'up' && this.upClass === 'disabled') return
            if (status === 'down' && this.downClass === 'disabled') return

            let temp = []
            for (let item of this.rightLayerArray) {
                if (this.rightCurrentSelectedLayer.indexOf(item) === -1) {
                    temp.push(item)
                }
            }

            this.rightCurrentSelectedLayer.sort((a, b) => {
                return this.rightLayerArray.indexOf(a) - this.rightLayerArray.indexOf(b)
            })

            let index = this.rightLayerArray.indexOf(this.rightCurrentSelectedLayer[0])
            status === 'up' ? index-- : index++
            this.rightLayerArray = [...temp.slice(0, index), ...this.rightCurrentSelectedLayer, ...temp.slice(index)]
        },

        /**
         * 向上或向下移动多步到顶或者到底
         * @param status
         */
        moveMoreStep(status) {
            if (status === 'up' && this.upClass === 'disabled') return
            if (status === 'down' && this.downClass === 'disabled') return
            let temp = []
            for (let item of this.rightLayerArray) {
                if (this.rightCurrentSelectedLayer.indexOf(item) === -1) {
                    temp.push(item)
                }
            }
            this.rightLayerArray = status === 'up' ?
                [...this.rightCurrentSelectedLayer, ...temp] :
                [...temp, ...this.rightCurrentSelectedLayer]
        },
    }
}
</script>

<style scoped lang="less">
.disabled() {
    cursor: not-allowed !important;
    background-color: #999 !important;
    border: #333 solid 1px !important;
}

.hover() {
    background-color: #eee;
    border: #409eff solid 1px;
    cursor: default;
}

.buttonContainer() {
    height: 200px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: center;
}

.active() {
    background-color: #409eff;
    color: #fff;
}

.container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    user-select: none;

    .layerContainer {
        width: 200px;
        height: 250px;
        border: #999 solid 1px;
        box-sizing: border-box;
        padding: 10px;
        white-space: nowrap;
        overflow-x: hidden;
        overflow-y: auto;

        div {
            &:hover {
                cursor: default;
            }

        }

        .active {
            .active()
        }
    }

    .centerButton {
        .buttonContainer();

        div {
            width: 30px;
            height: 30px;
            border: #666 solid 1px;
            background-color: #ddd;
            text-align: center;
            line-height: 30px;

            &:hover {
                .hover()
            }
        }
    }

    .transfer-right-buttons {

        .buttonContainer();

        div {
            width: 30px;
            height: 30px;
            border: #666 solid 1px;
            background-color: #ddd;

            img {
                width: 100%;
                height: 100%;
            }

            &:hover {
                .hover()
            }
        }

        .disabled {
            .disabled()
        }
    }
}
</style>

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

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

相关文章

Flink之时间语义

Flink之时间语义 简介 Flink中时间语义可以说是最重要的一个概念了,这里就说一下关于时间语义的机制,我们下看一下下面的表格,简单了解一下 时间定义processing time处理时间,也就是现实世界的时间,或者说代码执行时,服务器的时间event time事件时间,就是事件数据中所带的时…

LSTM模型

目录 LSTM模型 LSTM结构图 LSTM的核心思想 细胞状态 遗忘门 输入门 输出门 RNN模型 LRNN LSTM模型 什么是LSTM模型 LSTM (Long Short-Term Memory)也称长短时记忆结构,它是传统RNN的变体,与经典RNN相比能够有效捕捉长序列之间的语义关联,缓解梯度消失或爆炸现象.同时LS…

iOS自定义下拉刷新控件

自定义下拉刷新控件 概述 用了很多的别人的下拉刷新控件&#xff0c;想写一个玩玩&#xff0c;自定义一个在使用的时候也会比较有意思。使应用更加的灵动一些&#xff0c;毕竟谁不喜欢各种动画恰到好处的应用呢。 使用方式如下&#xff1a; tableview.refreshControl XRef…

【CTF-web】buuctf-[CISCN2019 华北赛区 Day2 Web1]Hack World(sql盲注)

题目链接 根据上图可知&#xff0c;页面中已经告诉我们要从flag表中的flag列取出flag&#xff0c;思考是sql注入。经过抓包发现发post包中的id字段是注入点。 经测试当输入id1时&#xff0c;结果为Hello, glzjin wants a girlfriend.&#xff0c;当id2时&#xff0c;结果为Do y…

Azure共享映像库构建VM镜像

什么是Azure共享映像库 Azure共享映像库是一项在Microsoft Azure中以共享方式存储和管理映像的服务。映像是预配置的虚拟机操作系统和应用程序的快照&#xff0c;可以用来创建多个虚拟机实例。通过将映像存储在共享映像库中&#xff0c;用户可以轻松地共享映像给其他Azure订阅…

MES管理系统如何帮助制造企业打造透明化工厂

在制造型企业的运营中&#xff0c;车间现场管理至关重要。然而&#xff0c;面临着信息传递速度慢、跨部门协作困难、生产进度无法及时掌握、制造品质不良、设备故障不能及时处理等困境&#xff0c;企业需要寻求有效的解决方案。MES生产管理系统作为针对制造企业车间生产过程控制…

REC 系列 Visual Grounding with Transformers 论文阅读笔记

REC 系列 Visual Grounding with Transformers 论文阅读笔记 一、Abstract二、引言三、相关工作3.1 视觉定位3.2 视觉 Transformer 四、方法4.1 基础的视觉和文本编码器4.2 定位编码器自注意力的文本分支文本引导自注意力的视觉分支 4.3 定位解码器定位 query 自注意力编码器-解…

教你手机摄影要知道的技巧

手机摄影已经成为人们记录生活、分享瞬间的重要方式之一。随着手机摄像头技术的不断提升&#xff0c;我们每个人都有机会成为优秀的手机摄影师。然而&#xff0c;要想在手机摄影领域脱颖而出&#xff0c;掌握一些关键的技巧是必不可少的。 1. 了解你的手机摄像头&#xff1a; …

使用percona-xtrabackup备份MySQL数据

xtrabackup备份分为两种 本文参考链接1 本文参考链接2 全量备份 1.备份数据 要创建备份&#xff0c;请xtrabackup使用xtrabackup --backup option. 您还需要指定一个xtrabackup --target-dir选项&#xff0c;即备份的存储位置&#xff0c;如果InnoDB数据或日志文件未存储在同…

Electron入门,项目启动。

electron 简单介绍&#xff1a; 实现&#xff1a;HTML/CSS/JS桌面程序&#xff0c;搭建跨平台桌面应用。 electron 官方文档&#xff1a; [https://electronjs.org/docs] 本文是基于以下2篇文章且自行实践过的&#xff0c;可行性真实有效。 文章1&#xff1a; https://www.cnbl…

Tomcat 为什么要破坏 Java 双亲委派机制?

大家好&#xff0c;我是锋哥!&#xff01; 我们分为4个部分来探讨: 什么是类加载机制&#xff1f;什么是双亲委任模型&#xff1f;如何破坏双亲委任模型&#xff1f;Tomcat 的类加载器是怎么设计的&#xff1f; 我想&#xff0c;在研究tomcat 类加载之前&#xff0c;我们复习…

java+springboot+mysql银行管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的银行管理系统&#xff0c;系统包含超级管理员、管理员、客户角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;客户管理&#xff1b;卡号管理&#xff08;存款、取款、转账&#xff09…

自动化安装系统(三)

Cobbler 简介 Cobbler是一款Linux生态的自动化运维工具&#xff0c;基于Python2开发&#xff0c;用于自动化批量部署安装操作系 统&#xff1b;其提供基于CLI的管理方式和WEB配置界面&#xff0c;其中WEB配置界面是基于Python2和Django框架开发。另外&#xff0c;cobbler还提…

Go语言基础之运算符

运算符用于在程序运行时执行数学或逻辑运算。 运算符 Go 语言内置的运算符有&#xff1a; 算术运算符关系运算符逻辑运算符位运算符赋值运算符

【Java】Spring——Bean对象的作用域和生命周期

文章目录 前言一、引出Bean对象的作用域1.普通变量的作用域2.Bean对象的作用域 二、Bean对象的作用域1.Bean对象的6种作用域2.设置Bean对象的作用域 三、Bean对象的生命周期总结 前言 本人是一个普通程序猿!分享一点自己的见解,如果有错误的地方欢迎各位大佬莅临指导,如果你也…

window安裝python2.7.0

官网下载安装 https://www.python.org/downloads/release/python-270/ 选中所有用户&#xff0c;然后点击next 切换安装位置&#xff0c;最好不要选择c盘 点击next 等待安装 安装完成 配置环境变量 将python安装路径添加到系统环境变量 cmd窗口输入python,会打开应用商…

unity Dropdown默认选择不选择任何选项

当我们使用Dropdown下拉框时&#xff0c;有时不需要有默认选项&#xff0c;把 value设置为-1就可以了&#xff0c; 但是用代码设置value-1是没有效果的&#xff0c;

Stochastic: Distribution-Expectation-Inequalities

见&#xff1a;https://www.math.hkust.edu.hk/~makchen/MATH5411/Chap1Sec2.pdf

创意灵感网站都有哪些?推荐这8个

设计师最痛苦的事情不是&#xff1a;改变草稿&#xff01;加班吧&#xff01;但创造力已经耗尽&#xff0c;没有灵感。对于创意设计师来说&#xff0c;浏览创意网站是寻找灵感创意的关键途径。但当你寻找灵感和创造力时&#xff0c;你会发现一些著名的创意网站只是展示了热门图…

利用console提高写bug的效率

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 自从入坑前端后&#xff0c;日常写bug就没离开过console。 要说用得多&#xff0c;不如说是console.log用得多&#xff0c;console.warn和console.erro…