效果图
代码
<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">></div><div @click="transferAllToRight">>></div><div @click="transferToLeft"><</div><div @click="transferAllToLeft"><<</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, refFunctionif (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') returnif (status === 'down' && this.downClass === 'disabled') returnlet 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') returnif (status === 'down' && this.downClass === 'disabled') returnlet 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>