圖解
html
1 <body> 2 <script src="./Dvue.js"></script> 3 <script> 4 const app = new DVue({ 5 data: { 6 test: "I am test", 7 foo: { 8 bar: "bar" 9 } 10 } 11 }) 12 13 app.$data.test = "hello world!" 14 // app.$data.foo.bar = "hello!" 15 </script> 16 </body>
Dvue.js
1 class DVue { 2 constructor(options) { 3 this.$options = options 4 5 // 數據響應化 6 this.$data = options.data 7 this.observe(this.$data) 8 9 // 模擬一下watcher創建 10 // 激活get 並將依賴添加到deps數組上 11 new Watcher() 12 this.$data.test 13 new Watcher() 14 this.$data.foo.bar 15 } 16 17 observe(value) { 18 // 判斷value是否是對象 19 if (!value || typeof value !== 'object') { 20 return 21 } 22 23 // 遍歷該對象 24 Object.keys(value).forEach(key => { 25 this.defineReactive(value, key, value[key]) 26 }) 27 } 28 29 // 數據響應化 30 defineReactive(obj, key, val) { 31 // 判斷val內是否還可以繼續調用(是否還有對象) 32 this.observe(val) // 遞歸解決數據嵌套 33 34 // 初始化dep 35 const dep = new Dep() 36 37 Object.defineProperty(obj, key, { 38 get() { 39 // 讀取的時候 判斷Dep.target是否有,如果有則調用addDep方法將Dep.target添加到deps數組上 40 Dep.target && dep.addDep(Dep.target) 41 return val 42 }, 43 set(newVal) { 44 if (newVal === val) { 45 return; 46 } 47 val = newVal 48 // console.log(`${key}屬性更新了:${val}`) 49 dep.notify() // 更新時候調用該方法 50 } 51 }) 52 } 53 } 54 55 56 // Dep: 用來管理Watcher 57 class Dep { 58 constructor() { 59 // 這里存放若干依賴(watcher) |一個watcher對應一個屬性 60 this.deps = []; 61 } 62 63 // 添加依賴 64 addDep (dep) { 65 this.deps.push(dep) 66 } 67 68 // 通知方法 69 notify() { 70 this.deps.forEach(dep => dep.update()) 71 } 72 } 73 74 // Watcher 75 class Watcher { 76 constructor () { 77 // 將當前watcher實例指定到Dep靜態屬性target上 78 Dep.target = this // 當前this就是Watcher對象 79 } 80 81 update() { 82 console.log('屬性更新了') 83 } 84 }