vue响应式原理

2019-02-24  本文已影响0人  hello_world_bye

参考: vue2.0源码分析之理解响应式架构
](https://segmentfault.com/a/1190000007334535)

// 参考:https://segmentfault.com/a/1190000007334535

function VNode(tag, data, children, text) {
  return {
    tag: tag,
    data: data,
    children: children,
    text: text
  }
}

class Vue {
  constructor(options) {
    this.$options = options
    this._data = options.data
    Object.keys(options.data).forEach(key => this._proxy(key))
    observer(options.data)
    // 调用watch方法时会执行render方法,该方法中会触发date[key]的get方法
    const vdom = watch(this, this._render.bind(this), this._update.bind(this))
  }
  _proxy(key) {
    const self = this
    Object.defineProperty(self, key, {
      configurable: true,
      enumerable: true,
      get: function proxyGetter () {
        return self._data[key]
      },
      set: function proxySetter (val) {
        _data[key] = val 
      }
    })
  }
  _update() {
    console.log("我需要更新");
    const vdom = this._render.call(this)
  }
  _render() {
    return this.$options.render.call(this)
  }
  __h__(tag, attr, children) {
    return VNode(tag, attr, children.map((child)=>{
      if(typeof child === 'string'){
        return VNode(undefined, undefined, undefined, child)
      }else{
        return child
      }
    }))
  }
  __toString__(val) {
    return val == null ? '' : typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val);
  }
}

function observer(value, cb){
  Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}

function defineReactive(obj, key, val, cb) {
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: ()=>{
      if(Dep.target){
        console.log('现在的值:', val)
        dep.add(Dep.target)
      }
      return val
    },
    set: newVal => {
      if(newVal === val)
        return
      val = newVal
      dep.notify()
    }
  })
}
function watch(vm, exp, cb){
  Dep.target = cb // Dep相当于是一个全局变量
  let vdom = exp()
  Dep.target = null //清空Dep,区别是普通的 get还是查找依赖时的 get
  return vdom
}

class Dep {
  constructor() {
    this.subs = []
  }
  add(cb) {
    this.subs.push(cb)
  }
  notify() {
    this.subs.forEach((cb) => cb())
  }
}
Dep.target = null
// --------------------
var demo = new Vue({
  el: '#demo',
  data: {
    text: "before",
  },
  render(){
    return this.__h__('div', {}, [
      this.__h__('span', {}, [this.__toString__(this.text)])
    ])
  }
})
 setTimeout(function(){
   demo.text = "after"
 }, 3000)
console.log('Dep.target', Dep.target)
console.log('demo.text', demo.text)
上一篇 下一篇

猜你喜欢

热点阅读