Vue:动态删除组件:移除最后一个组件而不是第一个,移 debugging 误的组件

kuhbmx9i  于 2023-05-07  发布在  Vue.js
关注(0)|答案(2)|浏览(193)

bounty还有6天到期。回答此问题可获得+50声望奖励。parsecer希望引起更多关注这个问题。

代码fiddlie:https://codesandbox.io/s/thirsty-austin-ty6f7i?file=/src/App.vue
我有一个简单的页面,允许用户更改3输入,并添加3图像:

App.vue

<template>
  <div>
    <div v-for="(line, i) in this.lines" class="line-wrapper" v-bind:key="i">
      <AddImageComponent
        class="add-image"
        matchType="image.*"
        selectButtonText="SELECT OR DROP AN IMAGE"
      />

      <input type="text" v-model="this.lines[i].text" />

      <div class="delete-button" v-on:click.stop="this.lines.splice(i, 1)">
        Delete
      </div>
    </div>
  </div>
</template>

<script>
import AddImageComponent from "./AddImageComponent.vue";
export default {
  name: "App",
  components: {
    AddImageComponent: AddImageComponent,
  },

  data() {
    return {
      lines: [{ text: "A" }, { text: "B" }, { text: "C" }],
    };
  },
};
</script>

<style>
#app {
  background-color: darkcyan;
  height: 100vh;
}

.add-image {
  background-color: lime !important;
  height: 50%;
}

.line-wrapper {
  background-color: purple;
  border: 2px solid black;
  margin-top: 2em;
}

.delete-button {
  background-color: red;
  padding: 5px;
  max-width: 50%;
  border-radius: 10px;
  border: 2px solid red;
}

.delete-button:hover {
  cursor: pointer;
  background-color: transparent;
  border: 2px solid red;
  color: white;
}

input {
  margin: 10px;
  background-color: yellow;
  padding: 5px;
  border-radius: 10px;
  border: none;
}
</style>

我看到的第一页是这样的:

当我添加图像时:

当我点击第一个(最上面的)Delete红色按钮时:

因此,当剩余元素的文本是BC(文本A被删除)时,图片是鸟和蛇,而不是蛇和狗(最后一个AddImageComponent被删除,而不是第一个)。
我不确定解决这个问题的最佳实践方法是什么。

6mzjoqzu

6mzjoqzu1#

假设key不是line的数组索引。为每个line成员添加一个唯一的id成员,并将其用作key属性:

data() {
  return {
    lines: [
      { id: 1, text: 'A' },
      { id: 2, text: 'B' },
      { id: 3, text: 'C' }
    ],
  };
},
<template>
  <div>
    <div v-for="(line, i) in this.lines" class="line-wrapper" v-bind:key="line.id">

活生生的例子

46scxncf

46scxncf2#

正如我在评论中提到的,使用key不是问题,而是如何使用它。将key绑定到迭代的index值并不是一件理想的事情。在模板中使用splicethis关键字在这种情况下也不理想。
注意你的脚本部分。lines是一个对象数组,text是唯一的属性。理想情况下,应该有一个唯一的属性来绑定key,例如id。所以我会提出两个解决方案

<template>
  <div>
    <div v-for="(line, i) in lines" class="line-wrapper" v-bind:key="line.text">
      <AddImageComponent
        class="add-image"
        matchType="image.*"
        selectButtonText="SELECT OR DROP AN IMAGE"
      />

      <input type="text" v-model="lines[i].text" />

      <div class="delete-button" v-on:click.stop="onDelete(line)">Delete</div>
    </div>
  </div>
</template>

请注意,我删除了模板中的this关键字,并将key绑定到中每一项的text属性。还要注意我在脚本中提供的onDelete方法。

export default {
  name: "App",
  components: {
    AddImageComponent: AddImageComponent,
  },

  data() {
    return {
      lines: [{ text: "A" }, { text: "B" }, { text: "C" }],
    };
  },
  methods: {
  // take note of this
    onDelete(item) {
      this.lines = this.lines.filter((line) => line.text !== item.text);
    },
  },
};
</script>

现在,此解决方案假设您在中的唯一属性为text。另一种方法是使用id作为唯一属性,并使用它代替text。总之,这里的解决方案还注意到我起飞的v型在使用中。它实际上会给你带来麻烦。在循环中使用v-model有几种方法,但不是你处理它的方式。我建议你在这里做一些阅读https://vuejs.org/guide/essentials/event-handling.html

<template>
  <div>
    <div v-for="(line, i) in lines" class="line-wrapper" v-bind:key="line.text">
      <AddImageComponent
        class="add-image"
        matchType="image.*"
        selectButtonText="SELECT OR DROP AN IMAGE"
      />

      <input type="text" :value="lines[i].text" @blur="(e) => onEdit(e, line)" />

      <div class="delete-button" v-on:click.stop="onDelete(line)">Delete</div>
    </div>
  </div>
</template>

<script>
import AddImageComponent from "./AddImageComponent.vue";
export default {
  name: "App",
  components: {
    AddImageComponent: AddImageComponent,
  },

  data() {
    return {
      lines: [{ text: "A" }, { text: "B" }, { text: "C" }],
    };
  },
  methods: {
    onEdit(e, item) {
      const value = e.target.value;
      this.lines = this.lines.map((line) => {
        if (line.text === item.text) {
          return {
            ...line,
            text: value,
          };
        }
        return line;
      });
    },
    onDelete(item) {
      this.lines = this.lines.filter((line) => line.text !== item.text);
    },
  },
};
</script>

<style>
#app {
  background-color: darkcyan;
  height: 100vh;
}

.add-image {
  background-color: lime !important;
  height: 50%;
}

.line-wrapper {
  background-color: purple;
  border: 2px solid black;
  margin-top: 2em;
}

.delete-button {
  background-color: red;
  padding: 5px;
  max-width: 50%;
  border-radius: 10px;
  border: 2px solid red;
}

.delete-button:hover {
  cursor: pointer;
  background-color: transparent;
  border: 2px solid red;
  color: white;
}

input {
  margin: 10px;
  background-color: yellow;
  padding: 5px;
  border-radius: 10px;
  border: none;
}
</style>

除了这次之外,其他解决方案都是相同的。我正在修改lines,使其具有唯一属性,例如id。我个人建议你遵循这种方法。

<template>
  <div>
    <div v-for="(line, i) in lines" class="line-wrapper" v-bind:key="line.id">
      <AddImageComponent
        class="add-image"
        matchType="image.*"
        selectButtonText="SELECT OR DROP AN IMAGE"
      />

      <input type="text" :value="lines[i].text" @blur="(e) => onEdit(e, id)" />

      <div class="delete-button" v-on:click.stop="onDelete(line.id)">Delete</div>
    </div>
  </div>
</template>

<script>
import AddImageComponent from "./AddImageComponent.vue";
export default {
  name: "App",
  components: {
    AddImageComponent: AddImageComponent,
  },

  data() {
    return {
      lines: [{ id: 1, text: "A" }, { id: 2, text: "B" }, { id: 3, text: "C" }],
    };
  },
  methods: {
    onEdit(e, id) {
      const value = e.target.value;
      this.lines = this.lines.map((line) => {
        if (line.id === item.id) {
          return {
            ...line,
            text: value,
          };
        }
        return line;
      });
    },
    onDelete(id) {
      this.lines = this.lines.filter((line) => line.id !== id);
    },
  },
};
</script>

<style>
#app {
  background-color: darkcyan;
  height: 100vh;
}

.add-image {
  background-color: lime !important;
  height: 50%;
}

.line-wrapper {
  background-color: purple;
  border: 2px solid black;
  margin-top: 2em;
}

.delete-button {
  background-color: red;
  padding: 5px;
  max-width: 50%;
  border-radius: 10px;
  border: 2px solid red;
}

.delete-button:hover {
  cursor: pointer;
  background-color: transparent;
  border: 2px solid red;
  color: white;
}

input {
  margin: 10px;
  background-color: yellow;
  padding: 5px;
  border-radius: 10px;
  border: none;
}
</style>

对于文档和参考资料,您可以查看vue文档。https://vuejs.org/guide/introduction.html

相关问题