如何在Vue.js中从数组中删除一个项目

127

我是一名新手,正在学习vue.js(2),目前正在开发一个简单的事件应用程序。我已经成功地添加了事件,但现在我想通过点击按钮来删除事件。

HTML

    <div class="list-group">

        <div class="list-group-item" v-for="event in events">
            <h4 class="list-group-item-heading">
                {{ event.name }}
            </h4>

            <h5>
                {{ event.date }}
            </h5>

            <p class="list-group-item-text" v-if="event.description">{{ event.description }}</p>

            <button class="btn btn-xs btn-danger" @click="deleteEvent(event)">Delete</button>
        </div>

    </div>
</div>

JS(Vue)

new Vue ({
    el: '#app',

    data: {
        events: [
            {
                id: 1,
                name: 'Event 1',
                description: 'Just some lorem ipsum',
                date: '2015-09-10'
            },
            {
                id: 2,
                name: 'Event 2',
                description: 'Just another lorem ipsum',
                date: '2015-10-02'
            }
        ],

        event: { name: '', description: '', date: '' }
    },

    ready: function() {

    },

    methods: {

        deleteEvent: function(event) {
                this.events.splice(this.event);
        },

        // Adds an event to the existing events array
        addEvent: function() {
            if(this.event.name) {
                this.events.push(this.event);
                this.event = { name: '', description: '', date: '' };
            }
        }

    } // end of methods

});

我曾尝试将事件传递给函数,然后使用slice函数删除其中一个元素,我认为这是从数组中删除某些数据的代码。使用简单按钮和onclick事件从数组中删除数据的最佳和最干净的方法是什么?


这个回答解决了你的问题吗?如何从数组中删除特定项? - ponury-kostek
9个回答

212

你使用了错误的方法来调用splice

splice函数有以下几种用法:

array.splice(start)

array.splice(start, deleteCount)

array.splice(start, deleteCount, itemForInsertAfterDeletion1, itemForInsertAfterDeletion2, ...)

这里的start是你想要开始操作的索引,而不是你想要删除的元素。你应该传递第二个参数deleteCount为1,这意味着:“我想从索引{start}开始删除1个元素”。

因此你最好使用以下方式:

deleteEvent: function(event) {
  this.events.splice(this.events.indexOf(event), 1);
}

而且,您正在使用参数,因此可以直接访问它,而不是使用this.event

但是这样做会在每次删除时查找不必要的indexOf,为了解决这个问题,您可以在v-for中定义index变量,然后传递它而不是事件对象。

即:

v-for="(event, index) in events"
...

<button ... @click="deleteEvent(index)"

而且:

deleteEvent: function(index) {
  this.events.splice(index, 1);
}

1
太棒了,我已经意识到我一直在错误地使用splice。你能告诉我splice和slice之间的区别吗?谢谢! - Giesburts
3
可以的。基本上,splice 修改了原始数组,而 slice 则创建了一个新的数组。更多信息请参见此处:http://www.tothenew.com/blog/javascript-splice-vs-slice/ - Edmundo Santos
4
感谢@EdmundoRodrigues 的这个提示:“_你可以在v-for中定义索引变量_”,正是因为有这样的宝藏,我喜欢 Stack Overflow。 - Valentine Shi
@ Edmundo Rodrigues 谢谢。真的很好。我只是用索引删除而不是对象的索引。非常感谢。 - priya_21
我认为这不是Vue.js的正确答案。你可以使用$delete方法。仅适用于2.2.0+版本:也适用于数组+索引。 - Syamlal

108

6
这是正确的方法,因为让Vue了解这个消息。 - insign
2
为什么文档中说“你很少需要使用它”,这是一个好的实践吗? - Miguel Stevens
@Notflip:通常情况下,您只需整体替换数组。 - Katinka Hesselink
这个解决方案对我有效,而slice(index,1)什么也没做。 - Yogi
1
@Roberto,slice和splice是不同的 :) - Evil Pigeon

57

不要忘记绑定key属性,否则总是会删除最后一个项目。

从数组中正确删除所选项目的方法:

模板

<div v-for="(item, index) in items" :key="item.id">
  <input v-model="item.value">
   <button @click="deleteItem(index)">
  delete
</button>

脚本

deleteItem(index) {
  this.items.splice(index, 1); \\OR   this.$delete(this.items,index)
 \\both will do the same
}

3
这真的应该是被选中的答案。我一直在想为什么这两个选项(splice或$delete)都不起作用,结果发现我没有设置正确的键。 - Lunyx
它肯定删除了某些东西,但当绑定还没有就位时,它开始做一些奇怪的事情。 - DZet
2
我花了4个小时想知道为什么最后一个元素总是被删除。谢谢你! - Carol-Theodor Pelu
3
我们注意到您不能使用循环索引作为:key值。例如,<div v-for="(item, index) in items" :key="index">是无效的。 - Hendrik Pilz
@HendrikPilz 我已经在键中使用了 item.id - Afraz Ahmad
我知道,我只是留下这个通知,因为我们错误地使用了索引,并且花了一些时间才发现问题。 - Hendrik Pilz

7
您可以通过ID删除项目。
<button @click="deleteEvent(event.id)">Delete</button>

在你的JS代码中

deleteEvent(id){
  this.events = this.events.filter((e)=>e.id !== id )
}

Vue将被观察的数组的变异方法封装起来,以便它们还会触发视图更新。更多详情,请点击此处
你可能认为这会导致Vue丢弃现有DOM并重新渲染整个列表 - 幸运的是,这不是这种情况。

对于Vue 3来说不太好。你将Proxy {[items]}转换为[Proxy {item},Proxy {item}]。 - padavan

6

当你使用输入框时,绑定它们会更有趣。如果你想了解如何在Vue2中进行插入和删除操作,请参考以下示例:

请查看js fiddle示例。

new Vue({
  el: '#app',
  data: {
    finds: [] 
  },
  methods: {
    addFind: function () {
      this.finds.push({ value: 'def' });
    },
    deleteFind: function (index) {
      console.log(index);
      console.log(this.finds);
      this.finds.splice(index, 1);
    }
  }
});
<script src="https://unpkg.com/vue@2.5.3/dist/vue.js"></script>
<div id="app">
  <h1>Finds</h1>
  <div v-for="(find, index) in finds">
    <input v-model="find.value">
    <button @click="deleteFind(index)">
      delete
    </button>
  </div>
  
  <button @click="addFind">
    New Find
  </button>
  
  <pre>{{ $data }}</pre>
</div>


2
为什么不完全省略该方法,例如:
v-for="(event, index) in events"
...
<button ... @click="$delete(events, index)">

2
你可以使用indexOf方法从数组中获取当前索引。
remove: function (event){
      this.events.splice(this.events.indexOf(event),1);
    },

1
<v-btn color="info" @click="eliminarTarea(item.id)">Eliminar</v-btn>

而对于您的JS:

this.listaTareas = this.listaTareas.filter(i=>i.id != id)

1
你的回答跟其他人差不多,没有更好的地方。因此发表这个回答是没有价值的。 - foxiris
@foxiris 不要打击用户发表他们的答案。如果你觉得这个解决方案没有帮助,那就算了吧。 - Rutvij Kothari
2
对于 Vue 3 来说不好。你需要将 Proxy{[items]} 转换为 [Proxy{item}, Proxy{item}]。 - padavan

0
Splice 是最好的方法,可以从特定索引位置移除元素。给定的例子已在控制台上测试过。
card = [1, 2, 3, 4];
card.splice(1,1);  // [2]
card   // (3) [1, 3, 4]
splice(startingIndex, totalNumberOfElements)

"startingIndex从0开始。"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接