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包含一组观察数组的变异方法,因此它们也将会触发视图更新,这些方法以下:vue
替换数组
变异方法,顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异方法,例如: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)
复制代码
为了解决第二类问题,可使用splice
bash
vm.items.splice(newLength)
复制代码
小发现:经过下标直接更改数组元素,没法触发渲染机制更新视图,但此时数组的值已经发生变化,若同时有其余数据更改致使从新渲染时,绑定数组的dom也会更新显示最新的数据dom
obj: {
name: '蒋',
age: '28'
}
复制代码
name和age两个属性从初始化的时候就已经肯定了,此时更改obj中的两个属性值是能够被监听到而且触发视图更新的; 若是经过js代码对obj对象添加一个新属性,那么当这个属性发生变化时是没法被监听到的,除非使用this.$set方法添加的新对象; 2. 数组也是一个对象,索引至关于对象属性的key值,可是vue在针对单一的数组时,是没有对该索引对应的值进行数据劫持的,因此直接更改数组元素的值没法被监听到, 而且不能触发视图更新,例如:测试
arr1: [1, 2, 3, 4];
经过arr1[0] = 666,没法被监听到
arr2: [
{
name: 'a'
},
{
name: 'b'
}
]
arr2[0].name = 'cc';
复制代码
此时的更改是能够被监听到,而且触发视图更新的ui
个人疑问:为何vue不对单一的数组元素进行数据劫持呢,亲测能够经过数据劫持的方式来触发set方法this
// 个人测试方式以下
------------- 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类spa
new Observer(value)
方法去处理该元素,就返回到最早类继续往下走; 从第4步就能发现为何经过索引改动数组的元素没法触发视图更新了Object.keys()
方法来遍历对象,而且调用 defineReactive(obj, keys[i])
方法Object.defineProperty()
方法去监听对象中的每一个属性;dep.notify()
方法,该方法就是去通知watcher触发update方法去从新渲染视图;// 因为浏览器兼容问题,Object.observe
方法不能起到监听数据变更,因此vue在实现的过程当中本身有封装了 Observe 类
3d
// 例一:一个简单的数组
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.forEach(item => {
console.log(item.status) // '下课', '下课', '下课', '下课', '下课', '下课'
})
},
deep: true
}
}
复制代码
经过上述例子能够发现: