Vue响应式:
组件data数据一旦变化,立刻触发视图的更新
实现数据驱动视图的第一步
1. 核心API - Object.defineProperty
基本用法
const data={}
var name='zhangsan'
Object.defineProperty(data,"name",{
get:function(){
console.log('get')
return name
},
set:function(newVal){
console.log('set')
name = newVal
}
})
console.log(data.name)
data.name="lisi"
console.log(data.name)
// get zhangsan
// set
// get lisi
在基本使用中,不能监听复杂对象和数组
2. 响应式需要监听对象(深度监听)、监听数组
实现思路:
- 定义触发视图更新的方法:updateView()
- 重新定义数组原型 -> 实现调用数组方法时触发视图更新
创建新新对象,原型指向oldArrayProperty,再扩展新新的方法,不会影响原型,不污染全局变量.
在新定义的数组原型用添加 updateView()
- 深度监听对象方法 observer()
判断是否是数组或对象类型,不是的话,直接返回
若是数组类型,指向自定义的数组原型
重新定义各个数据
- 自定义监听方法 defineReactive()
在 Object.defineProperty 中的set方法中添加 updateView()方法触发视图更新;
在调用set方法前,定义深度监听方法 observer() 实现
- 监听
准备一个对象数据
调用 深度监听对象方法 observer()
遍历对象每个属性,调用自定义监听方法 defineReactive()实现监听
实现代码:
// 触发更新视图
function updateView() {
console.log("视图更新")
}
//重新定义数组原型
const oldArrayProperty=Array.prototype;
// 创建新新对象,原型指向oldArrayProperty,再扩展新新的方法,不会影响原型
const arrProto = Object.create(oldArrayProperty);
['push','pop','shift','unshift','splice'].forEach(methodName=>{
arrProto[methodName] = function () {
updateView()//触发视图更新
oldArrayProperty[methodName].call(this,...arguments)//
// Array.prototype.push.call(this,...arguments) 真正数组原型的处理
}
});
// 定义自定义属性,监听起来
function defineReactive(target, key, value) {
//深度监听
observer(value)
Object.defineProperty(target, key,{
get(){
return value;
},
set(newValue){
if (value != newValue) {
// 设置新值时-监听
observer(value)
// 注意,value一直在闭包中,此处设置完之后,再get时也是会获取最新的值。
value = newValue
// 触发更新视图
updateView()
}
}
})
}
// 监听对象属性
function observer(target) {
if (typeof target != 'object' || target === null) {
// 不是对象或者数组
return target
}
if (Array.isArray(target)) {
// 将数组类型数据 指向 自定义的数组原型
target.__proto__ = arrProto
}
// 重新定义各个属性
for (const key in target) {
defineReactive(target, key, target[key])
}
}
// 准备数据
const data = {
name: "张三",
age: 20,
info:{
address:"北京" //深度监听
},
nums:[10,20,30]
}
// 监听数据
observer(data)
// 测试
// data.name = '李四'
// data.age = 22
// data.info.address = "上海" //深度监听
// data.x = '100' //新增属性 监听不到--所以有vue.set
// delete data.name //删除属性,监听不到 --所以有vue.delete
data.nums.push(4) //监听数组
3. Object.defineProperty的一些缺点
- 深度监听,需要递归到底,一次性计算量大
- 无法监听新增属性/删除属性【解决办法:Vue.set Vue delete,新增和删除后通知视图更新】
- 无法原生监听数组,需要特殊处理
vue 3.0 启用 Proxy
- Proxy有兼容性问题
- Proxy兼容性问题,无法polyfill
网友评论