提问人:Jacques Joubert 提问时间:11/5/2023 更新时间:11/5/2023 访问量:23
vue destroy 可排序元素
Vue Destroy Sortable Element
问:
总结
创建面板,并将图层添加到面板。尝试删除图层时 将删除面板中的最后一个图层,而不是图层项目 被选中销毁。
完整期刊:
了解 Vue.js 下三分之一图形控制器中的 control.html
control.html 文件是旨在创建和管理层的 Web 应用程序的关键组件。这个接口是使用 Vue.js 构建的,允许用户配置和设计具有高度自定义的层。
control.html 概述
control.html 页面具有用户友好的界面,其中包含多个部分,每个部分专门用于设计过程的特定方面:
“设计编辑器”部分:提供一个选择菜单,用于向面板添加各种面板元素。
正文部分特别具有交互性,因为它支持拖放功能,允许用户对面板元素重新排序。
问题:图层删除不正确
在 control.html 界面中遇到的一个值得注意的问题是删除了特定层。尝试从面板上移除特定图层时,未破坏正确的图层。
故障排除和解决方案
为了解决这个问题,采取了几个步骤来诊断和纠正这个问题:
索引验证:首先确认传递给 destroyLayer 方法的索引准确无误。这涉及添加控制台 .log 语句以输出当前索引并验证它们与预期目标的对齐情况。
唯一键:在 v-for 指令中,通过将 :key 属性绑定到每层的唯一属性(通常是 id,而不是数组索引)来为每一层提供唯一键。这有助于 Vue 清楚地识别每个 DOM 元素,保持重新排序和删除等操作的保真度。
简化的 destroyLayer 函数:destroyLayer 方法经过简化,可直接使用拼接删除图层,无需额外的反应性技巧(如 $set 或 $forceUpdate),这些技巧通常是不必要的,并且可能会掩盖反应性问题的根本原因。
https://jsfiddle.net/4vh80j35/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue.js Control Application</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.10.2/Sortable.min.js"></script>
<style>
.container {
border: 2px solid #000;
padding: 10px;
margin-top: 10px;
}
.panel {
border: 1px solid blue;
margin: 5px;
padding: 5px;
position: relative;
}
.destroy-btn {
color: white;
background-color: red;
padding: 2px 5px;
cursor: pointer;
position: absolute;
right: 5px;
top: 5px;
}
.layer {
border: 1px solid green;
margin: 3px;
padding: 3px;
position: relative;
background-color: #efefef;
}
.draggable-container {
min-height: 50px;
}
</style>
</head>
<body>
<div id="app">
<div class="editor">
<button @click="createPanel">Create Panel</button>
<div v-if="panels.length > 0">
<label for="panelSelect">Choose a panel to add a layer:</label>
<select id="panelSelect" v-model="selectedPanel">
<option v-for="(panel, index) in panels" :value="index">Panel {{ index + 1 }}</option>
</select>
<button @click="createLayer">Add Layer to Selected Panel</button>
</div>
</div>
<div class="container">
<div class="panel" v-for="(panel, pIndex) in panels" :key="`panel-${pIndex}`" :data-index="pIndex">
<span class="destroy-btn" @click="destroyPanel(pIndex)">[destroy]</span>
Panel {{ pIndex + 1 }}
<div class="draggable-container">
<div class="layer" v-for="(layer, lIndex) in panel.layers" :key="`layer-${lIndex}`">
Layer {{ lIndex + 1 }} (in Panel {{ pIndex + 1 }})
<span class="destroy-btn" @click.stop="destroyLayer(pIndex, lIndex)">[destroy]</span>
</div>
</div>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
panels: [],
selectedPanel: null
},
mounted() {
this.$nextTick(() => {
this.panels.forEach((_, index) => {
this.makeSortable(index);
});
});
},
methods: {
createPanel() {
const newPanelIndex = this.panels.push({ layers: [] }) - 1;
this.$nextTick(() => {
this.makeSortable(newPanelIndex);
});
if (this.selectedPanel === null) {
this.selectedPanel = 0;
}
},
createLayer() {
if (this.selectedPanel !== null && this.selectedPanel < this.panels.length) {
this.panels[this.selectedPanel].layers.push({});
}
},
makeSortable(panelIndex) {
const container = this.$el.querySelector(`.panel[data-index="${panelIndex}"] .draggable-container`);
Sortable.create(container, {
group: 'shared', // set the group to 'shared' for all containers
onAdd: (evt) => {
console.log(`New ${evt.newIndex} from ${evt.oldIndex} in panel`);
const item = this.panels[evt.oldIndex].layers.splice(evt.oldIndex, 1)[0];
this.panels[evt.newIndex].layers.splice(evt.newIndex, 0, item);
},
onUpdate: (evt) => {
const panelIndex = evt.to.dataset.index;
const item = this.panels[panelIndex].layers.splice(evt.oldIndex, 1)[0];
this.panels[panelIndex].layers.splice(evt.newIndex, 0, item);
},
});
},
destroyPanel(index) {
this.panels.splice(index, 1);
if (index === this.selectedPanel) {
this.selectedPanel = (this.panels.length > 0) ? 0 : null;
}
},
destroyLayer(panelIndex, layerIndex) {
console.log(`Attempting to destroy layer ${layerIndex} of ${this.panels[panelIndex].layers.length} in panel ${panelIndex}`);
if (panelIndex < this.panels.length) {
const layers = this.panels[panelIndex].layers;
if (layerIndex < layers.length) {
// Removes the layer from the panel
layers.splice(layerIndex, 1);
}
// If the panel becomes empty and it's the selected one, deselect it
if (!layers.length && this.selectedPanel === panelIndex) {
this.selectedPanel = null;
}
}
},
}
});
</script>
</body>
</html>
答:
在以下示例中,id 被添加到每个图层中,因此您可以观察到销毁:
new Vue({
el: '#app',
data: {
panels: [],
selectedPanel: null
},
mounted() {
this.$nextTick(() => {
this.panels.forEach((_, index) => {
this.makeSortable(index);
});
});
},
methods: {
createPanel() {
const newPanelIndex = this.panels.push({ layers: [] }) - 1;
this.$nextTick(() => {
this.makeSortable(newPanelIndex);
});
if (this.selectedPanel === null) {
this.selectedPanel = 0;
}
},
createLayer() {
if (this.selectedPanel !== null && this.selectedPanel < this.panels.length) {
const id = this.panels[this.selectedPanel].layers.length ? Math.max(...this.panels[this.selectedPanel].layers.map(o => o.id)) + 1 : 0
this.panels[this.selectedPanel].layers.push({id});
}
},
makeSortable(panelIndex) {
const container = this.$el.querySelector(`.panel[data-index="${panelIndex}"] .draggable-container`);
Sortable.create(container, {
group: 'shared', // set the group to 'shared' for all containers
onAdd: (evt) => {
console.log(`New ${evt.newIndex} from ${evt.oldIndex} in panel`);
const item = this.panels[evt.oldIndex].layers.splice(evt.oldIndex, 1)[0];
this.panels[evt.newIndex].layers.splice(evt.newIndex, 0, item);
},
onUpdate: (evt) => {
const panelIndex = evt.to.dataset.index;
const item = this.panels[panelIndex].layers.splice(evt.oldIndex, 1)[0];
this.panels[panelIndex].layers.splice(evt.newIndex, 0, item);
},
});
},
destroyPanel(index) {
this.panels.splice(index, 1);
if (index === this.selectedPanel) {
this.selectedPanel = (this.panels.length > 0) ? 0 : null;
}
},
destroyLayer(panelIndex, layerIndex) {
console.log(`Attempting to destroy layer ${layerIndex} of ${this.panels[panelIndex].layers.length} in panel ${panelIndex}`);
if (panelIndex < this.panels.length) {
const layers = this.panels[panelIndex].layers;
if (layerIndex < layers.length) {
// Removes the layer from the panel
layers.splice(layerIndex, 1);
}
// If the panel becomes empty and it's the selected one, deselect it
if (!layers.length && this.selectedPanel === panelIndex) {
this.selectedPanel = null;
}
}
},
}
});
.container {
border: 2px solid #000;
padding: 10px;
margin-top: 10px;
}
.panel {
border: 1px solid blue;
margin: 5px;
padding: 5px;
position: relative;
}
.destroy-btn {
color: white;
background-color: red;
padding: 2px 5px;
cursor: pointer;
position: absolute;
right: 5px;
top: 5px;
}
.layer {
border: 1px solid green;
margin: 3px;
padding: 3px;
position: relative;
background-color: #efefef;
}
.draggable-container {
min-height: 50px;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.10.2/Sortable.min.js"></script>
<div id="app">
<div class="editor">
<button @click="createPanel">Create Panel</button>
<div v-if="panels.length > 0">
<label for="panelSelect">Choose a panel to add a layer:</label>
<select id="panelSelect" v-model="selectedPanel">
<option v-for="(panel, index) in panels" :value="index">Panel {{ index + 1 }}</option>
</select>
<button @click="createLayer">Add Layer to Selected Panel</button>
</div>
</div>
<div class="container">
<div class="panel" v-for="(panel, pIndex) in panels" :key="`panel-${pIndex}`" :data-index="pIndex">
<span class="destroy-btn" @click="destroyPanel(pIndex)">[destroy]</span>
Panel {{ pIndex + 1 }}
<div class="draggable-container">
<div class="layer" v-for="(layer, lIndex) in panel.layers" :key="`layer-${lIndex}`">
Layer {{ lIndex + 1 }} (in Panel {{ pIndex + 1 }}) id: {{layer.id}}
<span class="destroy-btn" @click.stop="destroyLayer(pIndex, lIndex)">[destroy]</span>
</div>
</div>
</div>
</div>
</div>
评论
下一个:按标题中的字符数对列表进行排序
评论