看了一些关于vue3.0的更新内容,主要是围绕性能方面的提升和对MVVM数据绑定的完全重写。3.0中不再使用 Object.defineProperty 而是原生ES6 Proxy,关于Proxy
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
在vue2.x中,使用Object.defineProperty实现数据劫持。一般的做法如下:
let obj = {};
// 遍历data的所有属性
let dataKeys = Object.keys(data);
dataKeys.map(key => {
// 为data的所有属性添加set方法
Object.defineProperty(data, key, {
set: function(newVal) {
// 修改v-text属性对应的data中的key的值
document.querySelector(el + " *[v-text=" + key + "]").textContent = newVal;
}
});
});
// 将处理好的data赋值给要返回的对象
obj.data = data;
return obj;
上面的代码中可以看出,主要有两个问题:
- 要为对象的每一个属性添加数据劫持,一般结合Object.keys()遍历对象属性实现。如果对象的层级结构不是简单的层级结构,只能一直遍历处理。
- 不能监听数组的变化,数组的push, pop, shift, unshift, splice, sort, reverse等方法不会触发set的侦听。我们在使用vue修改数组时能触发view的更新是因为vue内部做了变相的处理。
针对Vue 3.0的这个更新,做了一个简单的单向数据绑定的例子,说明3.0中使用Proxy实现数据绑定的基本原理(只是简单的单向绑定,数据的更改会反映到视图上)
<div id="app">
<h1 v-text="title"></h1>
<p>当前时间:<span v-text="time"></span></p>
</div>
function ViewBind({ el = 'body', data = {}} = {}) {
// 要返回的对象实例
let obj = {};
const proxy = new Proxy(data, {
get(obj, property) {
return obj[property]
},
set(obj, property, newValue) {
obj[property] = newValue;
const bindEle = document.querySelector(el + " *[v-text=" + property + "]");
if (bindEle) {
bindEle.textContent = newValue;
}
}
});
obj.data = proxy;
return obj;
};
const app = new ViewBind({
el: '#app',
data: {
count: 0,
title: '这是标题',
time: +new Date()
}
});
setInterval(() => {
// 定时修改页面上<span v-text="time">元素中的内容
app.data.time = +new Date();
app.data.count = app.data.count + 1;
app.data.title = '这是标题' + app.data.count;
}, 1000)
上面的代码中通过ViewBind实例化了一个对象,定时修改对象的属性,视图上通过v-text绑定的内容就会自动更新,效果如下
评论 (0)