vue响应式双向绑定更新Dom实现

143 阅读1分钟

简单实现Vue响应式依赖收集和更新的派发

创建一个dep类添加依赖-和触发更新依赖

  class dep {
    constructor() {
      this.subs = new Set()
    }
    depend (sub) {
      this.subs.add(sub)
    }
    notify () {
      this.subs.forEach(sub => sub.update())
    }
  }

创建一个watcher类上面有update方法更新自己

class Watcher {
    constructor(cb) {
      this.cb = cb
    }
    update () {
      this.cb()
      console.log('更新', this.cb)
    }
  }

更新页面上的dom元素数据进行双向绑定

html元素

 <div id="app"></div>
 <input type="text" id="input" oninput="inputVal(event)" />

双向绑定更新input输入值-以及目标元素值插入修改

var dom = document.getElementById('app')
var input = document.getElementById('input')
function inputVal (e) {
    let val = e.target.value
    obj.a = val
  }
  function updateComponet (el, value) {
    el.innerHTML = value
  }

把对象各个属性值变成响应式使用observe方法

内部响应式的时候使用dep类收集了依赖

function observe (target) {
    var deps = new dep()
    deps.depend(real)

    Object.keys(target).forEach(key => {
      let defaultValue = target[key]
      Object.defineProperty(target, key, {
        get () {
          return defaultValue
        },
        set (newVal) {
         // target[key] = newVal  
          defaultValue = newVal
          deps.notify()
          // if(newVal === target[key]) return 
        }
      })
    })
  }
  observe(obj)

需要有一个更新组件目标的方法传入watcher实例

class Watcher {
   constructor(cb) {
     this.cb = cb
   }
   update () {
     this.cb()
     console.log('更新', this.cb)
   }
 }
 var real = new Watcher(() => {
     updateComponet(dom, obj.a)
  })

完整源码实现

<!DOCTYPE html>
<html lang="en">

<head>
 <meta charset="UTF-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
</head>

<body>
 <div id="app"></div>
 <input type="text" id="input" oninput="inputVal(event)" />
</body>
<script>
 var dom = document.getElementById('app')
 var input = document.getElementById('input')
 var obj = {
   a: '123'
 }

 function inputVal (e) {
   let val = e.target.value
   obj.a = val
 }
 function updateComponet (el, value) {
   el.innerHTML = value
 }
 class dep {
   constructor() {
     this.subs = new Set()
   }
   depend (sub) {
     this.subs.add(sub)
   }
   notify () {
     this.subs.forEach(sub => sub.update())
   }
 }

 class Watcher {
   constructor(cb) {
     this.cb = cb
   }
   update () {
     this.cb()
     console.log('更新', this.cb)
   }
 }
 var real = new Watcher(() => {
     updateComponet(dom, obj.a)
  })


 updateComponet(dom, obj.a)
 function observe (target) {
   var deps = new dep()
   deps.depend(real)

   Object.keys(target).forEach(key => {
     let defaultValue = target[key]
     Object.defineProperty(target, key, {
       get () {
         return defaultValue
       },
       set (newVal) {
         defaultValue = newVal
         deps.notify()
         // if(newVal === target[key]) return 
       }
     })
   })
 }
 input.value = obj.a
 observe(obj)


</script>
<style>
 #app {
   width: 100px;
   height: 100px;
   background: green;
 }
</style>

</html>