data () {
return {
nameList: ['jiang', 'ru', 'yi']
}
},
methods: {
handleClick () {
// 通过push,unshift等方法改变数组可以通过watch监听到
this.nameList.push('瑶')
// 直接通过数组下标进行修改数组无法通过watch监听到
this.nameList[2] = '爱'
// 通过$set修改数组可以通过watch监听到
this.$set(this.nameList, 2, '张')
// 利用数组splice方法修改数组可以通过watch监听到
this.nameList.splice(2, 1, '蒋如意')
}
},
watch: {
nameList (newVal) {
console.log(newVal)
}
}
Суммировать
Метод мутации
Vue включает в себя набор изменяющих методов, которые наблюдают за массивом, поэтому они также будут запускать обновления представления.Эти методы следующие:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
заменить массив
Методы мутации, как следует из названия, мутируют исходный массив, который был вызван этими методами. Напротив, существуют также неизменяющие методы, такие как filter(), concat() и slice(). Они не мутируют исходный массив, но всегда возвращают новый массив. При использовании неизменяющего метода вы можете заменить старый массив новым массивом.
Меры предосторожности
Из-за ограничений JavaScript Vue не может обнаружить следующие изменяющиеся массивы.
1. Когда вы используете индекс для прямой установки элемента, например: vm.items[index] = newValue
2. При изменении длины массива, например: vm.items.length = newLength
Для решения первого типа задач можно использовать следующие два способа.
// 方法一
Vue.set(vm.items, index, newValue)
Vue.splice(index, 1, newValue)
Для решения второго типа задач можно использовать сварку.
vm.items.splice(newLength)
Небольшое открытие: прямое изменение элементов массива с помощью подписки не может инициировать механизм рендеринга для обновления представления, но в это время значение массива изменилось.Если в то же время происходят другие изменения данных, когда вызывается повторный рендеринг, DOM, связанный с массивом, также будет обновлен для отображения последних данных.
Объяснить через представление vue
- Когда vue отслеживает данные, ему необходимо определить ключ свойства при инициализации данных и перехватить данные через Object.defineProperty, чтобы инициировать обновление представления при изменении данных, например:
obj: {
name: '蒋',
age: '28'
}
Два свойства name и age были определены с момента инициализации.В настоящее время можно отслеживать изменение значения двух свойств в obj и запускать обновление представления; Если к объекту obj через код js добавляется новое свойство, то при изменении этого свойства его нельзя будет отслеживать, если только новый объект не будет добавлен с помощью метода this.$set; 2. Массив также является объектом, а индекс эквивалентен ключевому значению свойства объекта, но когда Vue нацеливается на один массив, он не захватывает значение, соответствующее индексу, поэтому напрямую изменяет значение массива. элемент не может быть проконтролирован. и не может запускать обновления представлений, например:
arr1: [1, 2, 3, 4];
通过arr1[0] = 666,无法被监听到
arr2: [
{
name: 'a'
},
{
name: 'b'
}
]
arr2[0].name = 'cc';
Изменения в это время можно отслеживать и запускать обновления представления.
Мой вопрос:Почему vue не выполняет перехват данных на одном элементе массива?Протест может вызвать метод set путем перехвата данных
// 我的测试方式如下
------------- def开始 -----------------
function def (obj, key, val) {
var value = val
Object.defineProperty(obj, key, {
set (newVal) {
console.log('触发set')
value = newVal
},
get () {
return value
}
})
}
-------------- def结束 ----------------
var arr = [1, 2, 3]
arr.forEach((item, index) => {
def(arr, index, item)
})
arr[0] = 11
arr[1] = 22
console.log(arr) // [11, 22, 3]
-----------------------------
var obj = {
list: ['a', 'b', 'c']
}
obj.list.forEach((item, index) => {
def(obj.list, index, item)
})
obj.list[0] = 'jiang'
obj.list[1] = 'ru'
console.log(obj.list) // ['jiang', 'ru', 'c']
Объясните на уровне источника
// Из-за проблем с совместимостью браузера метод Object.observe не может отслеживать изменения данных, поэтому vue инкапсулирует класс Observe в процессе реализации.
- Значение, которое необходимо отслеживать, оценивается в методе конструктора класса Observer.
- Если значение является массивом, то вам нужно вызвать методObservArray для его обработки.
- МетодObserverArray в основном обходит каждый элемент массива и вызывает методObserver для обработки каждого элемента.
- Что делает метод наблюдения, так это то, что если элемент является простой строкой или числом, он ничего не делает и возвращается напрямую; если элемент является объектом, он вызывается
new Observer(value)
метод для обработки элемента, возврата к первому классу и продолжения вниз; Из шага 4 вы можете узнать, почему изменение элементов массива по индексу не может вызвать обновление представления. - Вернемся к Observer. Если будет установлено, что отслеживаемое значение не является массивом, вызовите метод walk для обработки элемента.
- Вызывается в методе ходьбы
Object.keys()
метод для перебора объекта и вызоваdefineReactive(obj, keys[i])
метод - Что делает метод defineReactive, так это использование
Object.defineProperty()
метод для прослушивания каждого свойства в объекте; - будет вызываться в методе set
dep.notify()
метод, который должен уведомить наблюдателя о необходимости запуска метода обновления для повторного рендеринга представления; - В методе get свойство будет добавлено к соответствующим зависимостям.
исходный код
// Из-за проблем с совместимостью браузераObject.observe
Метод не может отслеживать изменения данных, поэтому vue инкапсулирует класс Observe в процессе реализации.
- Значение, которое необходимо отслеживать, оценивается в методе конструктора класса Observer.
- Если значение является массивом, то вам нужно вызвать методObservArray для его обработки.
- МетодObserverArray в основном обходит каждый элемент массива и вызывает методObserver для обработки каждого элемента.
- Что делает метод наблюдения, так это то, что если элемент представляет собой простую строку или число, он ничего не делает и возвращается напрямую; если элемент является объектом, он вызывает метод new Observer(value) для обработки элемента и возвращается к первому Класс продолжает снижаться;
6. В методе walk вызывается метод Object.keys() для обхода объекта, а также вызывается метод defineReactive(obj, keys[i])
8. В методе set будет вызываться метод dep.notify(), который должен уведомить наблюдателя о необходимости запуска метода обновления для повторного рендеринга представления;
Как прослушать массив через часы
// 例一:一个简单的数组
data () {
return {
dataList: [1, 2, 3, 4]
}
},
methods: {
handleClick () {
this.dataList.forEach((item, index) => {
// 首先这里通过遍历数组改变元素的值,不能直接进行赋值更改,否则无法被监听到
// item = '你好'
// 需要用$set方法进行赋值
this.$set(this.dataList, index, '你好')
})
}
},
watch: {
dataList (newVal) {
console.log(newVal) // ['你好', '你好', '你好', '你好']
}
}
// 例二: 一个对象数组
data () {
return {
dataList: [
{
label: '一年级',
status: '上课'
},
{
label: '二年级',
status: '上课'
},
{
label: '三年级',
status: '上课'
},
{
label: '四年级',
status: '上课'
},
{
label: '五年级',
status: '上课'
},
{
label: '六年级',
status: '上课'
}
]
}
},
methods: {
handleClick () {
// 如果是对象数组,可以通过这种方法改变元素的值,并且能够触发视图更行
this.dataList.forEach(item => {
item.status = '下课'
})
}
},
watch: {
// dataList (newVal) { // 无法监听到数组变化
// newVal.forEach(item => {
// console.log(item.status)
// })
// },
dataList: { // 通过设置deep的值可以监听到
handler (newVal) {
newVal.forEach(item => {
console.log(item.status) // '下课', '下课', '下课', '下课', '下课', '下课'
})
},
deep: true
}
}
Из вышеприведенного примера можно узнать, что:
- Для одного простого массива, если вам нужно изменить значение элемента в нем, вам нужно изменить его с помощью метода this.$set, который можно отслеживать в это время и запускать обновление представления.
- Следует подчеркнуть, что если простой массив не изменяется с помощью метода this.$set, бесполезно, установлен ли в часах deep:true или нет, и изменения в массиве не могут быть отслежены.
- В примере 2 можно обнаружить, что в массиве объектов элементы в каждом объекте могут быть изменены напрямую и могут инициировать обновление представления, но если вам нужно отслеживать, изменяется ли массив с помощью наблюдения, вы должны добавить deep: true