Untitled
unknown
javascript
a year ago
6.1 kB
4
Indexable
<template>
<div class="main-container">
<h3>Панель элементов</h3>
<div class="elements-panel">
<div
v-for="element in elements"
:key="element.id"
class="panel-item"
:style="{ width: element.width * 50 + 'px' }"
draggable="true"
@dragstart="onDragStart($event, element.id, true)"
@dragend="onDragEnd"
>
{{ element.id }}
</div>
</div>
<h3>Сетка</h3>
<div class="grid-container">
<div
v-for="(cell, index) in grid"
:key="index"
class="grid-cell"
@dragover.prevent
@drop="onDrop($event, index)"
></div>
<div
v-for="(cell, index) in grid"
:key="'item-' + index"
v-if="cell !== null"
class="grid-item"
:style="{
left: cell.pos * 50 + 'px',
width: (cell.width * 50) + 'px'
}"
draggable="true"
@dragstart="onDragStart($event, cell.id, false)"
@dragend="onDragEnd"
@click="selectElement(cell)"
>
{{ cell.id }}
</div>
</div>
<div v-if="selectedElement" class="form-container">
<h3>Редактирование: {{ selectedElement.id }}</h3>
<label>
Ширина (ячейки):
<input type="number" v-model.number="newWidth" min="1" max="12" />
</label>
<button @click="applyWidthChange">Применить</button>
<button @click="removeElement">Удалить</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
grid: Array(12).fill(null),
elements: [
{ id: "a", width: 2 },
{ id: "b", width: 1 },
{ id: "c", width: 3 },
],
draggedElement: null,
draggedFromPanel: false,
selectedElement: null,
newWidth: null,
};
},
methods: {
onDragStart(event, id, fromPanel) {
if (fromPanel) {
this.draggedElement = this.elements.find((el) => el.id === id);
this.draggedFromPanel = true;
} else {
this.draggedElement = this.grid.find((cell) => cell && cell.id === id);
this.draggedFromPanel = false;
}
event.dataTransfer.setData("text/plain", id);
event.dataTransfer.effectAllowed = "move";
},
onDragEnd() {
this.draggedElement = null;
this.draggedFromPanel = false;
},
onDrop(event, dropPos) {
if (!this.draggedElement) return;
const element = this.draggedElement;
const { width } = element;
if (this.canPlace(dropPos, width, element)) {
if (this.draggedFromPanel) {
// Убираем элемент из панели
this.elements = this.elements.filter((el) => el.id !== element.id);
// Создаём новый объект, чтобы реактивно обновить
const newElement = { ...element, pos: dropPos };
this.$set(this.grid, dropPos, newElement);
} else {
// Перемещаем элемент внутри сетки
const oldPos = element.pos;
this.$set(this.grid, oldPos, null);
const updatedElement = { ...element, pos: dropPos };
this.$set(this.grid, dropPos, updatedElement);
// Если выбранный элемент был перемещён, обновим ссылку
if (this.selectedElement && this.selectedElement.id === element.id) {
this.selectedElement = updatedElement;
}
}
this.draggedElement = null;
} else {
alert("Невозможно разместить элемент здесь!");
}
},
canPlace(pos, width, element) {
if (pos + width > this.grid.length) return false;
for (let i = pos; i < pos + width; i++) {
const cellEl = this.grid[i];
if (cellEl !== null && cellEl !== element) {
return false;
}
}
return true;
},
selectElement(element) {
this.selectedElement = element;
this.newWidth = element.width;
},
applyWidthChange() {
if (!this.selectedElement) return;
const element = this.selectedElement;
const oldWidth = element.width;
const oldPos = element.pos;
const newW = this.newWidth;
// Удаляем с текущей позиции
this.$set(this.grid, oldPos, null);
const updatedElement = { ...element, width: newW };
if (this.canPlace(oldPos, newW, updatedElement)) {
this.$set(this.grid, oldPos, updatedElement);
this.selectedElement = updatedElement; // Обновляем ссылку
} else {
// Откат
this.$set(this.grid, oldPos, element);
alert("Недостаточно места для новой ширины");
}
},
removeElement() {
if (!this.selectedElement) return;
const element = this.selectedElement;
this.$set(this.grid, element.pos, null);
this.selectedElement = null;
},
},
};
</script>
<style scoped>
.main-container {
font-family: Arial, sans-serif;
padding: 20px;
}
.elements-panel {
display: flex;
margin-bottom: 20px;
}
.panel-item {
background: #ddd;
margin-right: 10px;
text-align: center;
cursor: grab;
height: 50px;
line-height: 50px;
border: 1px solid #aaa;
user-select: none;
}
.grid-container {
position: relative;
width: 600px;
height: 50px;
border: 1px solid #000;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
margin-bottom: 20px;
}
.grid-cell {
width: 50px;
height: 50px;
border-right: 1px dotted #ccc;
box-sizing: border-box;
position: relative;
}
.grid-cell:last-child {
border-right: none;
}
.grid-item {
position: absolute;
top: 0;
height: 50px;
background: #8cf;
border: 1px solid #44f;
display: flex;
align-items: center;
justify-content: center;
cursor: grab;
user-select: none;
box-sizing: border-box;
}
.form-container {
margin-top: 20px;
border: 1px solid #444;
padding: 10px;
background: #f9f9f9;
}
</style>Editor is loading...
Leave a Comment