vue3的mvvm实现原理是基于Proxy实现的,可比vue2的Object.defineProperty简明扼要不少,也很巧妙,demo不难,一步步实现吧,总共就一个js文件,不超过100行代码,要什么自行车。vue
更新视图的方法react
把数据变为响应式数据的方法数组
测试数据缓存
改变测试数据 触发更新视图方法框架
// 用最简化的模型来模式vue3的mvvm实现原理
// 用这个方法来模式视图更新
function updateView() {
console.log('触发视图更新啦')
}
// 把原目标对象 转变 为响应式的对象
function reactive(target) {
// todo 具体如何转变,以及绑定视图更新方法
let proxyed = new Proxy(target, options)
return proxyed
}
// 测试数据
let obj = {
name: 'Ace7523',
array: ['a', 'b', 'c']
}
// 把原数据转变响应式的数据
let reactivedObj = reactive(obj)
// 改变数据,指望会触发updateView() 方法 从而更新视图
reactivedObj.name = 'change'
复制代码
小结 准备工做算是作完了,接下来就是实现reactive方法,而后修改一下obj对象,看是否会触发updateView()方法mvvm
利用 new Proxy(target, options) 对target对象,进行数据改造测试
完善 optionsspa
// 用最简化的模型来模式vue3的mvvm实现原理
// 用这个方法来模式视图更新
function updateView() {
console.log('触发视图更新啦')
}
// 把原目标对象 转变 为响应式的对象
const options = {
set(target, key, value, reciver) {
updateView()
return Reflect.set(target, key, value, reciver)
},
get(target, key, reciver) {
return Reflect.get(target, key, reciver)
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key)
}
}
function reactive(target) {
// todo 具体如何转变,以及绑定视图更新方法
let proxyed = new Proxy(target, options)
return proxyed
}
// 测试数据
let obj = {
name: 'Ace7523',
array: ['a', 'b', 'c']
}
// 把原数据转变响应式的数据
let reactivedObj = reactive(obj)
// 改变数据,指望会触发updateView() 方法 从而更新视图
reactivedObj.name = 'change'
复制代码
小结 其实本质上就是不用Object.defineProperty 而改用别的方式来重写对象的get set方法了,也就是Proxy 的方式代理
添加的代码以下isObject()方法判断是不是对象,修改options.get()code
function isObject(t) {
return typeof t === 'object' && t !== null
}
// 把原目标对象 转变 为响应式的对象
const options = {
set(target, key, value, reciver) {
updateView()
return Reflect.set(target, key, value, reciver)
},
get(target, key, reciver) {
const res = Reflect.get(target, key, reciver)
if(isObject(target[key])){
return reactive(res)
}
return res
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key)
}
}
复制代码
小结 这里比较巧妙,建议对比下vue2中的Object.defineProperty的方法对比着看。
防止对数组添加数据时候,重复触发更新视图的方法
利用weakMap 记录原数据是否进行过代理,若是代理过,则返回记录值,再也不重复代理
// 用最简化的模型来模式vue3的mvvm实现原理
// 用这个方法来模式视图更新
function updateView() {
console.log('触发视图更新啦')
}
function isObject(t) {
return typeof t === 'object' && t !== null
}
// 把原目标对象 转变 为响应式的对象
const options = {
set(target, key, value, reciver) {
if(target.hasOwnProperty(key)){
updateView()
}
return Reflect.set(target, key, value, reciver)
},
get(target, key, reciver) {
const res = Reflect.get(target, key, reciver)
if(isObject(target[key])){
return reactive(res)
}
return res
},
deleteProperty(target, key) {
return Reflect.deleteProperty(target, key)
}
}
// 用来作缓存
const toProxy = new WeakMap()
function reactive(target) {
if(!isObject(target)){
return target
}
// 若是已经代理过了这个对象,则直接返回代理后的结果便可
if(toProxy.get(target)){
return toProxy.get(target)
}
let proxyed = new Proxy(target, options)
toProxy.set(target, proxyed)
return proxyed
}
// 测试数据
let obj = {
name: 'Ace7523',
array: ['a', 'b', 'c']
}
// 把原数据转变响应式的数据
let reactivedObj = reactive(obj)
// 改变数据,指望会触发updateView() 方法 从而更新视图
reactivedObj.name = 'change'
复制代码
小结 完整版代码暂时就这么多,没有考虑过多的边界条件,感兴趣的朋友能够复制出来玩玩看,改改测试数据看看会不会触发更新视图的方法~~~