1. 1什么是Proxy?
Proxy
直译过来就是代理的意思, Proxy
对象用来定义基本操作的自定义行为(如属性查找,枚举,赋值,函数调用等).它可以帮我们完成许多事情.例如对对象数据的处理.构造函数的数据验证,说白了就是我们访问对象前添加了一层拦截.我们可以对其进行许多操作.而这些由你自己定义.
基本语法
let proxy = new Proxy(target,handler)
参数
target
要使用Proxy包装的目标对象,(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
handler
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p
的行为。
下面是一个简单的实例
const obj = {name:"zs",age:434};
let proxy = new Proxy(obj,{
//obj 为目标对象, attr 为对象的属性
get(obj,attr){ //当我们获取代理对象的属性值是会走这个方法
return obj[attr]
},
// obj为目标对象, attr为属性名, value为属性值
set(obj,attr,value){//当我们设置代理对象的属性值是会走这个方法
if(property === "age"){
if(value >= 100 ) throw new Error("the data format is not correct")
obj[property] = value
}
//表示成功
return true
}
})
proxy.age = 120,
console.log(proxy.name )
上面的代码中当我们通过代理对象设置name属性值时, 会调用set方法,此时我们判断
设置的属性是不是age, 如果是,则判断age的值是不是大于100,如果是则抛出一个错误,当我们设置的数字不符合格式时, 我们设置的属性值就不会生效.只有当age设置的数字符合要求时,才能设置上属性值.
相当于我们对象添加了一层拦截,只有当我们的数据符合我们拦截是所设置的要求时,我们才能得到自己想要的结果.
代理对象相当于一层中介,我们不直接操作对象数据,而是通过这个代理对象操作数据.
1 2. 简单的数据双向绑定
了解了基本原理后,我们就可以通过代理来实现一个简单数据双向绑定
下面是代码的部分
假设我们HTML有如下结构代码
<input type="text" v-model="content">
<input type="text" v-model="title">
<input type="text" v-model="title">
<h3 v-bind="title"></h3>
下面是js代码部分
function view(option) {// 接受一个参数对象
this.initData = option.data;// 给实例对象添加初始化数据对象
let proxy = new Proxy(this.initData, {
set(obj, prototype, value) {// 当我们设置proxy的属性名时会走这个方法
//更新视图
document
.querySelectorAll(`[v-model="${prototype}"]`)// 获取相应的表单元素
.forEach((item) => {
item.value = value
})
document.querySelectorAll(`[v-bind="${prototype}"]`)// 获取相应的普通的标签元素
.forEach((item) => {
item.innerHTML = value
})
return true
},
get(obj, prototype) { }
})
this.data = proxy;
// 初始化绑定监听事件
this.init = function () {
let els = document.querySelectorAll("[v-model");
els.forEach((item) => {
item.addEventListener("input", function () {
// 此时通过getAttribute获取的是我们绑定在DOM元素上的属性值, 也就是相对应数据的属性名
proxy[this.getAttribute("v-model")] = this.value
})
})
}
// 初始化渲染
this.renderInit = function () {
for (let key in this.initData) {//对数据进行遍历, 获取key获取相应的DOM元素并更新视图.
let renerList = document.querySelectorAll(`[v-model="${key}"]`);
let renerInputList = document.querySelectorAll(`[v-bind="${key}"]`);
renerInputList.forEach((item) => item.innerHTML = this.initData[key])
renerList.forEach((item) => item.value = this.initData[key])
}
}
this.renderInit()// 渲染视图
}
let data = {
title: "张三434",
content: "43",
}
let vm = new view({
data,//传递的数据对象, ES6简写方式, 当属性名和属性值相同时,可以简写这种形式.
})
vm.init()
//我们通过实例对象上的data属性改变title属性值, 此时也会被代理对象所拦截并响应.
vm.data.title = "$34"
上面代码我们通过给构造函数传递的参数option的data属性, 给实例化对象身上添加了一个initData属性, 然后对实例对象的initData对象添加了一层代理. 然后给实例对象上添加一个data属性指向这个代理对象, 当我们通过实例的data属性改变相应的数据时,此时代理对象也会拦截到, 并更新相应的视图.
我们通过给实例对象添加了一个init初始化方法, 当我们调用init方法时,会获取页面上使用属性使用了v-model的元素,并为他们添加了input事件, 当这个事件触发的时候,我们通过获取当前元素v-model绑定的数据名. 和value值.来相应的设置proxy代理对象的键值对, 此时我们代理对象的set方法会调用, 通过传递过来的属性名, 获取相应的需要动态显示的元素,然后给相应的DOM元素更新视图.
网友评论