<template>
<div id="equipmentDeployment">
<div class="data">
{{ data }} {{ selected }}
</div>
<div class="container">
<div
class="row"
v-for="row in data"
:class="{ 'enter': enterId === row.id }"
@mouseover="handleMouseOver(row)"
@mouseleave="handleMouseLeave(row)">
<div
class="col"
v-for="col in row.children ?? []"
:id="col.id"
:class="{ selected: selected.has(col.id) }"
@click="handleClickItem(col)"
@mousedown="handleMouseDown(col)">
{{ col.id }}
</div>
</div>
<div ref="draggingDom" v-show="dragging" class="draggingDom row" :style="draggingStyle"></div>
</div>
</div>
</template>
<script setup>
import { onMounted, onUnmounted } from "vue";
const data = $ref(
new Array(10).fill(0).map((_, i) => ({
id: "id" + i,
children: new Array(3).fill(0).map((_, j) => ({ id: "id" + i + "_" + j })),
}))
);
const dataMapById = $ref({});
const parentMap = $computed(() => {
const map = {};
generatorDataMap(data, (item) => {
item?.children?.forEach((child) => {
map[child.id] = item;
});
});
return map;
});
const generatorDataMap = (arr, fn) => {
arr.forEach((item) => {
fn(item);
item.children?.length && generatorDataMap(item.children, fn);
});
};
generatorDataMap(data, (item) => (dataMapById[item.id] = item));
const selected = $ref(new Set());
let dragging = false;
let isCtrl = false;
let enterId = $ref(null);
let event = $ref(null);
const draggingDom = $ref(null);
const draggingStyle = $computed(() => ({
left: event?.x - 50 + "px",
top: event?.y - 50 + "px",
}));
onMounted(() => {
document.onkeydown = null;
document.onkeyup = null;
addKeyEvent();
});
onUnmounted(() => {
dispose();
});
const addKeyEvent = () => {
// 键盘按下事件
document.onkeydown = (e) => {
// 取消默认事件
e.preventDefault();
//事件对象兼容
let e1 = e || event || window.event || arguments.callee.caller.arguments[0]
//键盘按键判断:左箭头-37;上箭头-38;右箭头-39;下箭头-40 回车:13 ctrl:17 shift:16
switch (e1.keyCode) {
case 17:
isCtrl = true;
break;
}
}
// 键盘抬起事件
document.onkeyup = (e) => {
// 取消默认事件
e.preventDefault();
//事件对象兼容
let e1 = e || event || window.event || arguments.callee.caller.arguments[0]
switch (e1.keyCode) {
case 17:
isCtrl = false;
break;
}
}
};
const handleClickItem = (item) => {
if(!isCtrl) return;
selected.has(item.id)? selected.delete(item.id) : selected.add(item.id);
};
const generatorDraggingDom = () => {
[...selected].forEach((id) => {
const dom = document.querySelector("#" + id);
draggingDom.appendChild(dom.cloneNode(true));
});
};
const handleMouseMove = (e) => {
if (!dragging) return;
event = e;
};
const handleMouseUp = (e) => {
window.removeEventListener("mouseup", handleMouseUp);
window.removeEventListener("mousemove", handleMouseMove);
Array.from(draggingDom.children).forEach((childDom) => draggingDom.removeChild(childDom));
dragging = false;
event = null;
if(!enterId) return;
handleDrop();
enterId = "";
};
const handleMouseDown = (data) => {
if (!selected.has(data.id) || isCtrl) return;
dragging = true;
window.addEventListener("mouseup", handleMouseUp);
window.addEventListener("mousemove", handleMouseMove);
generatorDraggingDom();
};
const handleMouseOver = (data) => {
if (!dragging) return;
enterId = data.id;
};
const handleMouseLeave = (e) => {
if (!dragging) return;
enterId = "";
};
const handleDrop = () => {
[...selected].forEach((id) => {
const parent = parentMap[id];
const idx = parent.children.findIndex((child) => child.id === id);
parent.children.splice(idx, 1);
dataMapById[enterId].children?.push(dataMapById[id]);
});
selected.clear()
};
const dispose = () => {
window.removeEventListener("mouseup", handleMouseUp);
window.removeEventListener("mousemove", handleMouseMove);
};
</script>
<style lang="scss" scoped>
#equipmentDeployment {
width: 100%;
height: 100%;
overflow: auto !important;
display: flex;
gap: 12px;
user-select: none;
color: #fff;
.data {
width: 200px;
}
.container {
flex: 1;
display: flex;
gap: 12px;
flex-direction: column;
.row {
display: flex;
padding: 8px;
gap: 8px;
min-height: 104px;
border: 1px solid #ccc;
&.enter {
background: orange;
}
.col {
cursor: pointer;
width: 100px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #ccc;
&.selected {
border-color: green;
color: green;
}
}
}
.draggingDom {
position: fixed;
pointer-events: none;
}
}
}
</style>
12-12
146

03-06
164

09-28
2382
