# 参考
# 一、知识回顾
# 1、代理/劫持
- 数据代理
数据代理主要用于将组件的数据和属性访问委托给 Vue 实例本身,以便在访问和修改组件数据时可以触发 Vue 的响应式系统;
- 数据劫持
数据劫持主要用于拦截和处理组件数据的访问和修改操作,以便在数据变化时可以通知 Vue 响应式系统更新视图
# 2、vue2 缺陷
问题描述:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
解决方案:
- 对象类型:通过
Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)。 - 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)
快速演示
<template>
<div>
对象:{{person}} <br />
数组:{{hobby}} <br />
<button @click="addSex">新增属性</button>
<button @click="deleteAge">删除属性</button>
<button @click="updateHobby">数组操作</button>
<br />
</div>
</template>
<script>
export default {
data() {
return {
person: {
name: 'lencamo',
age: 20
},
hobby: ['喝酒', '吉他', '游泳']
}
},
methods: {
addSex() {
// 无效(页面不更新)
// this.person.sex = '男'
// 解决
this.$set(this.person, 'sex', '男')
// Vue.set(this.person, 'sex', '男')
},
deleteAge() {
// 无效(页面不更新)
// delete this.person.age
// 解决
this.$delete(this.person, 'age')
// Vue.delete(this.person, 'sex', '男')
},
updateHobby() {
// 无效(页面不更新)
this.hobby[0] = '睡觉'
// 解决
this.$set(this.hobby, 0, '睡觉')
// this.hobby.splice(0,1,'睡觉')
}
}
}
</script>
# 二、响应式原理
# 1、前情回顾
上一章节,我们已经提到了:
对象(或数组)类型数据, 它内部会自动通过 reactive() 转为代理对象
那 reactive()可以解决 vue2 中的响应式问题吗?
猜想验证
<div id="app">
对象:{{person}} <br />
数组:{{hobby}} <br />
<button @click="addSex">新增属性</button>
<button @click="deleteAge">删除属性</button>
<button @click="updateHobby">数组操作</button>
<br />
</div>
<script>
const { createApp, reactive } = Vue
createApp({
setup() {
let person = reactive({
name: 'lencamo',
age: 20
})
let hobby = reactive(['喝酒', '吉他', '游泳'])
function addSex() {
// 有效
person.sex = '男'
}
function deleteAge() {
// 有效
delete person.age
}
function updateHobby() {
// 有效
hobby[0] = '睡觉'
}
return {
person,
hobby,
addSex,
deleteAge,
updateHobby
}
}
}).mount('#app')
</script>
关于它是如何解决的,那就得从它的原理说起了
当然,现在我们已经知道了 reactive()是使用了 Proxy 对象
# 2、实现原理
- 通过 Proxy(代理) (opens new window): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
- 通过 Reflect(反射) (opens new window): 对源对象的属性进行操作。
提示
具体使用,可以参考笔记Proxy(代理) (opens new window)、Reflect(反射) (opens new window)
- 示例
let username = '数据劫持'
let age = 21
let person = {
username: username,
age: age
}
// 1、采用Proxy
let p = new Proxy(boj, {
get(target, key) {
// return target[key]
// 2、采用Reflect
return Reflect.get(target, key)
},
set(target, key, value) {
// target[key] = value
Reflect.set(target, key, value)
},
deleteProperty(target, key) {
// return delete target[key]
return Reflect.deleteProperty(target, key)
}
})