简版vue的reactive模块

66 阅读1分钟

简版vue的reactive模块

1、reactive实践

// 将传入的obj,动态设置一个key,它的值val

function defineReactive(obj, key, val) {
  // 递归
  observe(val)
  
  Object.defineProperty(obj, key, {
    get() {
      console.log('get', key);
      return val
    },
    set(v) {
      if (val !== v) {
        console.log('set', key);
        // 传入新值v可能还是对象
        observe(v)
        val = v
      }
    },
  })
}
// 递归遍历obj,动态拦截obj的所有key
function observe(obj) {
  if (typeof obj !== 'object' || obj == null) {
    return obj
  }
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key])
  })
}
// this.$set()
// Vue.set()
function set(obj, key, val) {
  defineReactive(obj, key, val)
}

2、demo 1

const obj = {
  foo: 'foo',
  bar: 'bar',
  baz: {
    a: 1
  }
}
// defineReactive(obj, 'foo', 'foo')
observe(obj)

// obj.foo
// obj.foo = 'fooooooo'
// obj.baz.a
// obj.baz = { a: 10 }
// obj.baz.a
// obj.dong = 'dong'
// obj.dong
// set(obj, 'dong', 'dong')
// obj.dong

3、最简单的响应式

<div id="app">
  {{foo}}
</div>
<script>
  function defineReactive(obj, key, val) {
    Object.defineProperty(obj, key, {
      get() {
        // console.log('get', key);
        return val
      },
      set(v) {
        if (val !== v) {
          val = v
          update()
        }
      },
    })
  }

  function update() {
    app.innerText = obj.foo
  }
  
  const obj = {}
  defineReactive(obj, 'foo', 'foo')

  setInterval(() => {
    obj.foo = new Date().toLocaleTimeString()
  }, 1000)
</script>