Официальный сайт объясняет следующее
Из-за ограничений JavaScript Vue не может обнаружить следующие изменяющиеся массивы: Когда вы устанавливаете элемент напрямую с помощью индекса, например: vm.items[indexOfItem] = newValue При изменении длины массива, например: vm.items.length = newLength
Потому что отзывчивость vue черезObject.definePropertyЧтобы добиться этого, свойство length массива не может добавлять геттеры и сеттеры, поэтому о нем нельзя судить, наблюдая за длиной.
пример
Следующий код, хотя кажется, что длина массива равна 10, но только 0, 1, 2 могут быть пройдены при for in, в результате чего только первые три индекса добавляются с помощью геттеров и сеттеров
var a = [0, 1, 2]
a.length = 10
// 只是显示的给length赋值,索引3-9的对应的value也会赋值undefined
// 但是索引3-9的key都是没有值的
// 我们可以用for-in打印,只会打印0,1,2
for (var key in a) {
console.log(key) // 0,1,2
}
Затем vue предоставляет некоторые решения
Используйте встроенный Vue.$set
Пусть массив явно соблюдает определенный индекс Vue.set(массив, indexOfItem, новое значение)
на самом деле называется
Object.defineProperty(array, indexOfItem, {
enumerable: true,
configurable: true,
get() { },
set(newVal) { }
})
Таким образом, вы можете вручную указать ключ, который необходимо соблюдать, тогда можно будет добиться ожидаемого эффекта.
Переопределить методы push, pop, shift, unshift, splice, sort, reverse.
Исходный код Vue
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
/**
* Intercept mutating methods and emit events
*/
;[
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()
return result
})
})
Это методы, переопределенные или добавленные в Array.__proto__
И для метода добавления таких свойств, кактолкать, раскладывать, сращиватьДобавленные новые свойства проверяются вручную, исходный код
if (inserted) ob.observeArray(inserted)
Ручной запуск сообщений для вышеуказанных методов
ob.dep.notify()
В заключение
Vue не может напрямую наблюдать за прямым изменением длины массива, он предоставляет vue.$set для явного наблюдения и переписывает методы push, pop, shift, unshift, splice, sort, reverse для неявного наблюдения.