手写基础版Vue响应式原理 曾经终败给现在 2022-12-20 03:11 89阅读 0赞 ## 1. 定义测试对象 ## 我们新建了一个obj对象,然后`new Observe` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>0</h1> <script src="./index.js"></script> <script> const obj = { a: 1, b: 2, c: 3 } new Observe(obj) </script> </body> </html> ## 2. 定义Observe观察者 ## let count = 0 function Observe (ops) { // 这里的ops就是我们的obj,提取ops对象中的所有键名组成的数组 const keys = Object.keys(ops) // 循环遍历这个key数组 for (let i = 0; i < keys.length; i++) { // 取到每一个key const key = keys[i] // 定义响应式 ops => obj, key => 对象的键名,ops[key] => 对象的键值 defineRective(ops, key, ops[key]) } } ## 3. 定义defineRective响应式函数 ## function defineRective (obj, key, value) { // 给传过来的值定义get/set Object.defineProperty(obj, key, { get () { console.log(1) return value }, set (val) { console.log(2) value = val } }) } ## 4. 定义更新页面的方式(假设) ## // 假设这里是更新页面的方法 function update () { // 获取到页面的h1元素 const h1 = document.querySelector('h1') // h1.innerHtml >>> 0 是将字符串转为数字 h1.innerHTML = `我已经更新了${ ++count} 次了` } ## 5. 测试 ## 现在我们可以测试一下,读取obj中的值,获取设置obj中的值,看看能不能打印 const obj = { a: 1, b: 2, c: 3 } new Observe(obj) console.log(obj.a) obj.a = 4 console.log(obj.a) ## 浏览器打印如下: i am get 1 i am set i am get 4 没问题 ## 6. 更新视图(假设) ## 那么既然读取对象中的数据就要刷新页面,那么我们这里就测试一下,读取一次页面就加1,我们可以在get/set中调用这个这个函数,达到更新视图的作用 function defineRective (obj, key, value) { // 给传过来的值定义get/set Object.defineProperty(obj, key, { get () { update() // 更新页面 console.log('i am get') return value }, set (val) { update()// 更新页面 console.log('i am set') value = val } }) } ## 7. 优化defineRective响应式函数 ## 之前我们测试的是普通的对象,假设现在我们里面对象嵌套对象,那么我们的代码能否实现响应式呢?我们可以测试一下 const obj2 = { a: { f: 'hello' }, b: { g: '华哥头发呢?' }, c: 3 } new Observe(obj2) console.log(obj2.a.f) console.log(obj2) // 经过打印obj2发现,只有第一层对象有get/set,所有并没有实现深度相应 // 那么我们就可以深度遍历一下,如果对象的值还是一个对象的话,我们可以递归调用Observe函数来为我们的对象添加get/set方法 // 响应式 function defineRective (obj, key, value) { // 如果值还是一个对象的话,递归调用一下 if (typeof value === 'object') Observe(value) // 给传过来的值定义get/set Object.defineProperty(obj, key, { get () { update() // 更新页面 console.log('i am get') return value }, set (val) { update()// 更新页面 console.log('i am set') value = val } }) } ## 结尾 ## 下期我们来讲讲 用Proxy来代替Object.defineProperty的优势,敬请期待!!
还没有评论,来说两句吧...