小型mvvm实现原理

关键词:

defineReactive:数据劫持,用来监听获取数据set和get,其中,get将实现发布订阅直接的绑定,set则发布事件,实现订阅者更新

Watcher:观察者,绑定Dept,在dept调用notify时候,触发Watcher回调

Dept:依赖关系,在数据更新的时候(set),调用自身的观察回调函数

具体代码如下

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>MVVM</title>
</head>
<body>
  <div></div>
  
</body>
<script>
  // 通过 Dep 解耦
class Dep {
  constructor() {
    this.subs = []
  }
  addSub(sub) {
    // sub 是 Watcher 实例
    this.subs.push(sub)
  }
  notify() {
    this.subs.forEach(sub => {
      sub.update()
    })
  }
}
// 全局属性,通过该属性配置 Watcher
Dep.target = null

function update(value) {
  document.querySelector('div').innerText = value
}

class Watcher {
  constructor(obj, key, cb) {
    // 将 Dep.target 指向自己
    // 然后触发属性的 getter 添加监听
    // 最后将 Dep.target 置空
    Dep.target = this
    this.cb = cb
    this.obj = obj
    this.key = key
    this.value = obj[key] // 触发obj的get方法,与dep联系起来
    Dep.target = null
  }
  update() {
    // 获得新值
    this.value = this.obj[this.key]
    // 调用 update 方法更新 Dom
    this.cb(this.value)
  }
}
function observe(obj) {
  // 判断类型
  if (!obj || typeof obj !== 'object') {
    return
  }
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key])
  })
}

function defineReactive(obj, key, val) {
  // 递归子属性
  observe(val)
  let dp = new Dep()
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      console.log('get value')
      // 将 Watcher 添加到订阅
      if (Dep.target) {
        dp.addSub(Dep.target)
      }
      return val
    },
    set: function reactiveSetter(newVal) {
      console.log('change value')
      val = newVal
      // 执行 watcher 的 update 方法
      dp.notify()
    }
  })
}
var data = { name: 'yck' }
observe(data)
// // 模拟解析到 `{{name}}` 触发的操作
new Watcher(data, 'name', update)
// // update Dom innerText
// data.name = 'yyy'



</script>
</html>

具体逻辑分析如下

原文地址:https://www.cnblogs.com/peace1/p/15046423.html