VueJS Reminder App 和独立更新数据数组项

VueJS Reminder App and Update data array items independently

这是我关于 VueJS 的第二个问题。我会把我的问题分成两部分。

1.为什么 VueJS 方法不断被调用或 运行 在循环中? 我认为 startTimer() 将在加载时被调用一次。每当我在数组中推送新提醒时,都会不断调用并冻结浏览器。我想我不了解 VueJS 中的方法,谁能详细说明一下?

2。如何为数据数组 (items) 中的单个列表项更新 timer/counter? 为了跟踪计时器和计数器,我在数据数组(项)中创建了元素,如您在代码笔中所见。

Codepen

<div id="reminders">
    <form v-on:submit.prevent="addReminder">
        <label for="new-reminder">Reminder</label>
        <input v-model="newReminder" type="text" id="new-reminder" placeholder="Feed the cat">
        <label for="new-timer">Time</label>
        <input v-model="newTimer" type="number" id="new-timer" placeholder="Time in minute"> 
        <button>Add</button>
    </form>
    <ul>
        <li v-for="item,index in items" class="reminder" v-bind:id='"reminder_"+item.id' v-bind:load="startTimer(index)"> 
            {{ item.id }}<span class="title">{{ item.title }}</span>
            TIMER: <span class="time">{{ item.time }}</span><br>
            COUNTER:<span class="counter">{{ item.counter }}</span><br>
            <button class="close" v-on:click="removeReminder(index)"><img src="https://image.flaticon.com/icons/svg/53/53804.svg" alt=""></button>
        </li>
    </ul>
</div> 

var reminder = new Vue({
    el: '#reminders',
    data: {
        newReminder: '',
        newTimer: 0,
        items: []
    },
    methods: {
        addReminder: function() {
            this.items.push({
                id: this.items.length,
                title: this.newReminder,
                time: this.newTimer,
                counter:0
            })
        },
        removeReminder: function(index) {
            this.items.splice(index, 1);
        },
        startTimer: function(index) {  
          if(this.items[index].counter<100)this.items[index].counter++; // if I don't do this. browser will freez and crash after sometime
          console.log(this.items[index].counter);
        }
    }
});

带定时器和计数器的替代代码 -

var reminder = new Vue({
    el: '#reminders',
    data: {
        newReminder: '',
        newTimer: 0,
        items: []
    },
    methods: {
        addReminder: function() {
            this.items.push({
                id: this.items.length,
                title: this.newReminder,
                time: this.newTimer,
                counter:0
            })
        },
        removeReminder: function(index) {
            this.items.splice(index, 1);
        },
        startTimer: function(index) {
            let item = this.items[index];
            let t = 0; 
            function timeout() {
                setTimeout(function() {
                    if (t == item.time * 60) {
                        $('#' + index).find('.title').css('text-decoration', 'line-through');
                    } else {
                        timeout();
                        item.counter = t++;
                        $('#' + index).find('.counter').text(item.time * 60 - item.counter);
                    }
                }, 1000);
            }
            timeout();
        }
    }
}); 
  1. 我不认为我们可以使用 v-bind:load 在元素挂载到 dom 时触发。您可以通过删除 v-bind:load 来修复,但会触发 addTimer 方法中的 this.startTimer(this.items.length - 1)

  2. 你应该 Vue.set(this.items, index, counter++);

https://vuejs.org/v2/api/#Vue-set

因此,我根据@Dat Tran 的建议修改代码并稍作修改,从而解决了我的示例,并且成功了。任何正在研究这个问题的人,这个解决方案可能对他们有用。

var reminder = new Vue({
    el: '#reminders',
    data: {
        newReminder: '',
        newTime: 0,
        items: []
    },
    methods: {
        addReminder: function() {
            let reminder = {
                id: this.items.length,
                title: this.newReminder,
                time: this.newTime,
                counter:0
            };
            Vue.set(this.items,this.items.length,reminder);  
            this.startTimer(this.items.length-1);
        },
        removeReminder: function(index) {
            this.items.splice(index, 1);
        },
        startTimer: function(index) {    
          setTimeout(()=> {
            console.log(this.items);
             if ( this.items[index].counter == parseInt(this.items[index].time)*60) {
                $('#reminder_' + index).find('.title').css('text-decoration', 'line-through');
            } else { 
                this.startTimer(index);
                this.items[index].counter++;
                console.log(this.items[index].counter);
                $('#reminder_' + index).find('.counter').text(this.items[index].time * 60 - this.items[index].counter);
            }
          }, 1000);  
        }
    }
});