一:现象
<template>
<button @click="change">改变</button>
</template>
<script>
export default {
data() {
return {
arr: [1, 2, 3]
}
},
watch: {
arr: {
handler: function (newData, oldData) {
console.log('change', newData, oldData)
},
deep: true
}
},
methods: {
change() {
this.arr.push('1111')
}
}
}
</script>
<style>
</style>
期望打印出来的应该是更新后的值和更新前的值,但是实际结果如下:
可以看出打印出来的新值和旧值是一样的。这是因为:
二:解决
通过官方解释,解决办法如下:
1.使用序列化和反序列化进行深拷贝
<template>
<button @click="change">改变</button>
</template>
<script>
export default {
data() {
return {
arr: [1, 2, 3]
}
},
computed: {
// 利用计算属性+序列化和反序列化进行处理
newArr() {
return JSON.parse(JSON.stringify(this.arr))
}
},
watch: {
newArr: {
handler: function (newData, oldData) {
console.log('change', newData, oldData)
},
deep: true
}
},
methods: {
change() {
this.arr.push('1111')
}
}
}
</script>
<style>
</style>
可以明显看出是有效果的,但是这种深拷贝方式存在一些问题,比如在数据为undefined等特殊值时会报错,将NaN序列化成null等问题。所以,我们来看第二种解决办法:
2.手写深拷贝
<template>
<button @click="change">改变</button>
</template>
<script>
export default {
data() {
return {
arr: [1, 2, 3],
obj: undefined
}
},
computed: {
// 使用计算属性进行深拷贝
newArr() {
return this.deepClone(this.arr)
}
},
watch: {
newArr: {
handler: function (newData, oldData) {
console.log('change', newData, oldData)
},
deep: true
}
},
methods: {
change() {
this.arr.push('1111')
},
//手写深拷贝
deepClone(value) {
let target = null
if (!this.isArray(value) && !this.isObject(value)) {
target = value
}
if (this.isArray(value)) {
target = []
for (let i = 0; i < value.length; i++) {
target[i] = this.deepClone(value[i])
}
}
if (this.isObject(value)) {
target = {}
for (let key in value) {
target[key] = this.deepClone(value[key])
}
}
return target
},
isArray(value) {
return Object.prototype.toString.call(value) === '[object Array]'
},
isObject(value) {
return Object.prototype.toString.call(value) === '[object Object]'
}
}
}
</script>
<style>
</style>
打印出来也是成功的。