vue.js 删除 v-for 中某个元素

html:

<div id="demo">
    <ul>
        <li v-for="item in items">
            <span>{ item.id }</span>
            <span>{ item.msg }</span>
            <span v-show="item.ok"> ok</span>
        </li>
    </ul>
</div>

js:

var viewModel = new Vue({
    el :'#demo',
    data: {
        items:[
            { msg : '列表1', ok: 1, id: 1},
            { msg : '列表2', ok: 2, id: 2},
            { msg : '列表3', ok: 0, id: 3}
        ]
    }
});<br></br>

加载之后, 渲染出列表,

然后我想从 items 中删除 id = 1 的这条数据,

Vue.js 包装的变异方法, 好像没有能直接删除的方法, 只有通过数组 key 才可以..

请问, 这得怎么实现?

sodasix

我把 HTML 结构改成这样了

 <ul>
        <li v-for="item in items">
            <span>{ $index }</span>
            <span data-id="{ item.id }" data-index="{ $index }">{ item.id }</span>
            <span>{ item.msg }</span>
            <span v-show="item.ok"> ok</span>
        </li>
    </ul>

然后删除的时候

viewModel.items.splice($('span[data-id="1"]').data('index'),1);

不知道, 有没有更优雅的办法…

sqrtqiezi

不要操作DOM,操作数据,让Vue负责视图的更新:

<div id="demo">
    <ul>
        <li v-for="item in items">
            <span>  item.id  </span>
            <span>  item.msg  </span>
            <span v-show="item.ok"> ok</span>
            <a href="javascript:;" @click="del(item)">del</a>
        </li>
    </ul>
</div>

<script>
    var viewModel = new Vue({
        el :'#demo',
        data: {
            items:[
                { msg : '列表1', ok: 1, id: 1},
                { msg : '列表2', ok: 2, id: 2},
                { msg : '列表3', ok: 0, id: 3}
            ]
        },
        methods: {
            del: function (item) {
                this.items.$remove(item)
            }
        }
    });
</script>
sqrtqiezi

@sodasix
好像我对问题理解有误,如果是socket.io传递过来的id进行同步的话,建议你通过id在items里查找到对应的item,然后丢给Vue封装的变异方法。
一楼的代码问题:一是,业务代码跟html结构耦合了,而Vue的响应式数据绑定在努力消除这种耦合;二是,为了这么小的事情引入jQuery确实不太优雅。
Happy hacking ~

lyon

@sqrtqiezi 确实,Vue是数据驱动刷新。思路有点类似于TODO list时,点击删除,触发相应的函数。

lyon

可以看看我的这个01-at-a-glance代码借鉴下。代码传送门

sodasix

@lyon
我看了下, 你的方法是在 列表中有一个 删除的按钮, 但是我是没有按钮的,
而且根据文档所说, .$remove(), 也是对 splice() 方法的封装, 原理也是先找到对应的下标吧…

 <button type="button" v-on:click="del($index)">del</button>

del: function(item){
                this.items.splice(item, 1);
                // this.items.$remove(item)
            }

这样会比直接传入一个 item 会更效率吧??

sodasix

@sqrtqiezi

通过id在items里查找到对应的item,然后丢给Vue封装的变异方法。

你说的应该也是 this.items.$remove(item) 这个方法吧?

我觉得还是直接通过 $index 的方式, 会更加效率, 只不过 jq 以及 HTML 耦合的问题, 还应该再想想其他途径…

Tomoe

@sodasix
這是我的理解,包含在外部去呼叫內部方法的實現
https://jsfiddle.net/ykx088Lv/2/

<div id="app">
    <ul>
      <li v-for="item in items">
        <span>{ item | json}</span>
        <a @click="deleteByIndex($index)">[delete it]</a>
      </li>
    </ul>
</div>
var app = new Vue({
    el: '#app',
    data: {
    	items: [
        	{ id: 4, text: 'item one'},
            { id: 5, text: 'item two'},
        	{ id: 6, text: 'item three'},
            { id: 7, text: 'item four'},
        ]
    },
    methods: {
        deleteByIndex: function(index) {
    	    this.items.splice(index, 1)
        },
        deleteById: function(id) {
        	var index = this.items.findIndex(item => item.id === id)
            this.deleteByIndex(index)
        }
  }
})

// 外部呼叫

// 刪除最後一個 (by Index
app.deleteByIndex(app.$data.items.length - 1)

// 刪除指定id ( by id
app.deleteById(4)
Osub 回复 Tomoe

这个解决了我的一个难题,谢谢

lyon

@sodasix T T, 效率问题。不知道耶。用户的电脑应该都很快把。
我看了下源码,在第2015行

   /**
   * Convenience method to remove the element at given index or target element reference.
   *
   * @param {*} item
   */

  def(arrayProto, '$remove', function $remove(item) {
    /* istanbul ignore if */
    if (!this.length) return;
    var index = indexOf(this, item);
    if (index > -1) {
      return this.splice(index, 1);
    }
  });
lyon

源码341行

 /**
   * Manual indexOf because it's slightly faster than
   * native.
   *
   * @param {Array} arr
   * @param {*} obj
   */

  function indexOf(arr, obj) {
    var i = arr.length;
    while (i--) {
      if (arr[i] === obj) return i;
    }
    return -1;
  }
sodasix

@Tomoe

this.items.find(item => item.id === id)

这个有点6 , 带我看看

Tomoe

@sodasix

突然發現自己不小心打錯惹

應該是

// 回傳匹配item的index
this.items.findIndex(item => item.id === id)

才對

findIndex和find都是ES6才有的特性,如果是ES6之前版本可以用filter

lyon

@Tomoe 老司机

Tomoe

@lyon
不敢當XD,剛好最近用vue開發,碰到類似情況