首页 > 解决方案 > Vue:从 v-for 列表中删除项目会留下画布项目

问题描述

这在标题中很难表达,但通过一些设置很容易解释。

我有一个组件列表。列表中的每个组件如下所示:

| [Canvas Preview] Name      (Delete button) |

每个组件都有一个小画布元素,用于显示项目的预览、它的名称和一个删除按钮,用于将其从列表中删除。v-for 迭代的列表存储在 Vuex 中。

使用字母表示不同的预览图像,列表可能如下所示:

| [W] Item 1      (Delete button) |
| [X] Item 2      (Delete button) |
| [Y] Item 3      (Delete button) |
| [Z] Item 4      (Delete button) |

当删除按钮被按下时,适当的项目被拼接出列表并且列表更新。名称会更新,单击它们会导致选择正确的项目。问题是预览保持在相同的位置。例如,如果我从上面的列表中删除了第 2 项(带有预览 X),我将得到以下列表:

| [W] Item 1      (Delete button) |
| [X] Item 3      (Delete button) |
| [Y] Item 4      (Delete button) |

预览是 WXY,当 X 被删除后它们应该是 WYZ。基本上,画布以相同的顺序保持不变,并且无论从何处删除项目,都只是将其删除。

当一个项目被删除时,我可以想到一些重绘所有画布的黑客方法,但我想知道是否有更好的解决方案。

编辑:这是删除项目的代码

项目上的删除按钮向列表组件发出事件

<button @click="deleteAsset">Delete</button>

deleteAsset(event){
    event.stopPropagation();
    this.isRenaming = false;
    this.$emit('deleteAsset', this.asset);
},

Wrapper 然后派发 Vuex 动作

deleteAsset(asset){
    this.$store.dispatch('GameData/deleteAsset', {category: asset.category_ID, id: asset.ID});
    this.updateAsset();
},

Vuex 动作和变异

//Action
deleteAsset({commit}, {category, id}){
    commit('deleteAsset', {category, id})
}

//Mutation
deleteAsset: (state, {category, id}) => {
    let curList = getList();
    let hasFound = false;

    for (let i = 0; !hasFound && i < curList.length; i++){
        if (curList[i].ID == id){
            curList.splice(i, 1);
            hasFound = true;
        }
    }
}

这是该问题的屏幕截图: Vue问题截图

其余数据是正确的,因为我添加了一个快速测试功能,可以在点击时打印当前 ID 和数据,并且一切都正确打印。看起来它只是没有改变的画布元素。

编辑 2:vue 代码

//List
<Asset
    ref="assets"
    v-for="asset in selectedList"
    :key="asset.cat_ID"
    :asset="asset"
    :defaultIcon="selected_category.icon"
    @deleteAsset="deleteAsset"
    @selectAsset="selectAsset"/>

//Asset code
<template>
    <div ref="asset" class="asset" :class="{selected : isSelected}" @click="selectAsset">
        <div class="leftFloat">
            <canvas v-show="hasThumb" class="thumbnail" ref="thumbNail" width="20" height="20">Test</canvas>
            <img v-if="!hasThumb" class="thumbnail assetIcon" :src="require(`@/${defaultIcon}.svg`)" />
            <div v-if="isRenaming">
                <input ref="renameText" v-model="asset.name" type="text" />
            </div>
            <div v-else>{{asset.name}}</div>
        </div>
        <div class="rightFloat">
            <button class="rightButton" @click="deleteAsset">
                <img class="rightIcon" src="@/assets/trash.svg" />
            </button>
        </div>
    </div>
</template>

标签: javascriptvue.jshtml5-canvas

解决方案


假设cat_ID可以分配给多个资产,您将遇到使用它的问题,因为如果您的任何资产中重复key发生列表更改,Vue 将无法检测到列表更改。cat_IDselectedList

由于您的资产具有ID属性,因此您应该在您的资产中使用它key

<Asset
  ref="assets"
  v-for="asset in selectedList"
  :key="asset.ID"
  :asset="asset"
  :defaultIcon="selected_category.icon"
  @deleteAsset="deleteAsset"
  @selectAsset="selectAsset"/>

key

key特殊属性主要用作 Vue 的虚拟 DOM 算法在将新节点列表与旧列表进行比较时识别 VNode的提示。在没有键的情况下,Vue 使用一种算法来最小化元素移动,并尝试尽可能多地就地修补/重用相同类型的元素。使用键,它将根据键的顺序更改对元素进行重新排序,并且不再存在键的元素将始终被删除/销毁。


推荐阅读