Vue.js update only works if other property changed

2019-08-01 19:09发布

I was wondering what a good approach is for my situation. Consider the following code:

<div id="app-4">
  <ol>
    <li v-for="todo in todos">
      {{ todo.text }} + {{todo.added_text}} <button v-on:click="add_text(todo)">do</button>
    </li>
  </ol>
</div>

<script type="text/javascript">
    var app4 = new Vue({
        el: '#app-4',
        data: {
            todos: [
              { text: 'Learn JavaScript' },
              { text: 'Learn Vue' },
            ]
        },
        methods: {
            add_text(item){
                index = this.todos.indexOf(item);
                this.todos[index].added_text = "something else";
                // this.todos[index].text = 'learn more';
            }
        }
    })
</script>

I want to add the todo.added_text if the button is pressed. But, because this property was not part of the elements in the array when vue was instantiated, this property does not appear at all (this is my assumption, I could be wrong).

However, when I change something else in the same element (e.g. the commented line: this.todos[index].text = 'learn more';), then both todo.text and todo.added_text update.

My question is, what is a good approach to tell vue that something changed in the element, besides changing some other property of the same element?

2条回答
三岁会撩人
2楼-- · 2019-08-01 19:47

But, because this property was not part of the elements in the array when vue was instantiated, this property does not appear at all

Yes you're right

When you pass a plain JavaScript object to a Vue instance as its data option, Vue will walk through all of its properties and convert them to getter/setters using Object.defineProperty.

The getter/setters are invisible to the user, but under the hood they enable Vue to perform dependency-tracking and change-notification when properties are accessed or modified.

Vue cannot detect property addition or deletion. Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the data object in order for Vue to convert it and make it reactive.

You do this with Vue.set(object, key, value) For example

Vue.set(vm.someObject, 'b', 2)

Read here

查看更多
smile是对你的礼貌
3楼-- · 2019-08-01 20:09

You can get reactivity by assigning to a reactive element. this.todos[index] is already reactive, so if you reassign the whole thing, all pieces will be reactive. Because it is an array element, you have to use set, but you can use it once for the whole object rather than for each added member:

        add_text(item){
            const index = this.todos.indexOf(item);
            const newObject = Object.assign({}, item, {
                text: 'learn more',
                added_text: 'something else'
            });

            this.$set(this.todos, index, newObject);
        }
查看更多
登录 后发表回答