Объект изменения Vue в массиве и реактивность срабатывания

Как я могу вызвать обновление при изменении части объекта, найденного по индексу в массиве?

Документы показывают, как изменить значение массива:

Vue.set(example1.items, indexOfItem, newValue)

или же

example1.items.splice(indexOfItem, 1, newValue)

Но как изменить значение свойства объекта в массиве, не меняя остальную часть объекта?

Следующее работает для обновления свойства, но Vue не реагирует на изменение, пока что-то еще не инициирует обновление.

example1.items[indexOfItem].some_object_property = false

Ответ 1

Пока вы вызываете set() один раз, чтобы установить объект (с тем свойством, которое вы собираетесь обновлять) в массиве, Vue будет реагировать на изменения свойств объекта. Вот пример, который имеет один массив объектов, инициализированных в наших данных приложения, и еще один массив объектов, установленных вручную (с Vue.set()) при монтировании. Нажатие кнопки обновляет свойство на одном объекте в каждом из этих массивов, а Vue реагирует. Обратите внимание, что вызов set(), который происходит в mount(), действительно может произойти в любое время.

https://codepen.io/jordan-kalosal/pen/VrwjoR

new Vue({
  el: "#app",
  data: {
    arr: [
      {
        property: 'OBJ1 Prop'
      },
      {
        property: 'OBJ2 Prop'
      }
    ],
    setLater: false
  },
  mounted() {
    this.$set(this, 'setLater', [
      {
        property: 'setLater OBJ1 Prop'
      },
      {
        property: 'setLater OBJ2 Prop'
      }
    ])
  },
  methods: {
    _updateObjProps() {
      this.arr[0].property = (new Date()).toString();
      this.setLater[0].property = (new Date()).toString();
    }
  }
})

Ответ 2

Вы можете обновить под-свойство в элементе массива с помощью this.$set(). Например, чтобы увеличить субсвойство x в первых двух элементах массива (создавая вспомогательное свойство, если оно не существует):

methods: {
  update() {
    this.$set(this.arr[0].foo, 'x', (this.arr[0].foo.x || 0) + 100)
    this.$set(this.arr[1].foo, 'x', (this.arr[1].foo.x || 0) + 100)
  }
}

new Vue({
  el: '#app',
  data() {
    return {
      arr: [
        {
          foo: {
            x: 100,
            y: 200
          }
        },
        {
          foo: {
            /* x does not exist here initially */
            y: 400
          }
        }
      ]
    };
  },

  methods: {
    update() {
      this.$set(this.arr[0].foo, 'x', (this.arr[0].foo.x || 0) + 100)
      this.$set(this.arr[1].foo, 'x', (this.arr[1].foo.x || 0) + 100)
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>

<div id="app">
  <button @click="update">Update</button>
  <p>arr[0]: {{ arr[0] }}</p>
  <p>arr[1]: {{ arr[1] }}</p>
</div>

Ответ 3

Вот еще один демонстрационный пример, который, я думаю, дает хорошую иллюстрацию реактивности объектов внутри массива. Попробуйте это здесь: https://codepen.io/antoniandre/pen/ZdjwKG

JS

new Vue({
  el: "#app",
  data: {
    array: []
  },

  methods: {
    addTimeProp() {
      this.array.forEach(item => {
        this.$set(item, 'time', null)
      })
    },
    updateObjectProp() {
      this.array.forEach(item => {
        item.time = (new Date()).toString()
      })
    }
  },

  created () {
    this.array.push({ name: 'today' }, { name: 'tomorrow' })
  }
})

HTML: PUG

#app
  h1 Reactivity of objects inside an array
  h2 Content of the array
  pre {{ array }}
  button(@click="array.push({ name: 'another day' })") Add another object
  button(@click="addTimeProp") Add 'time' property
  button(@click="updateObjectProp") Update 'time' property