Skip to content

13.VM 构造函数

wushufen edited this page May 29, 2019 · 1 revision

VM 构造函数

  1. options.data 的数据拷到 vm
  2. methods 注入 vm.$render 并拷到 vm
  3. mouted 等注入 vm.$render
  4. compile 编译模板生成 render
  5. createVnode, each 放到原型传入 render
  6. vm.$render 里进行异步 dom diff
  7. 如果支持 Proxy 则使用返回的是 proxy 方便在在控制台调试
  8. vm.$el 存在,则关联其到 dom diff,并初始渲染
  // VM class
  function VM(options) {
    var vm = this
    vm.$options = options || (options = {})

    // data
    var data = options.data
    if (typeof data === 'function') data = data.call(vm) // compoment data()
    assign(vm, data)

    // methods
    each(options.methods, function (fn, key) {
      vm[key] = injectRender(vm, fn)
    })

    // hooks
    each(options, function (fn, key) {
      if (typeof fn === 'function') {
        vm[key] = injectRender(vm, fn)
      }
    })

    // $el
    if (options.el) {
      vm.$el = options.el
    }

    // tpl
    var tplNode = options.el
    if (options.template) {
      tplNode = parse(options.template)
    }

    // render: options.render || compile
    var render = options.render
    if (!render) {
      tplNode = tplNode || {}
      render = options.render = compile(tplNode)
    }

    // async render
    vm.$render = function () {
      // update computed
      // each(options.computed, function (fn, key) {
      //   vm[key] = fn.call(vm)
      // })

      // trigger watch

      // dom diff update view
      cancelAnimationFrame(render.timer)
      render.timer = requestAnimationFrame(function () {
        var vnode = options.__vnode = render.call(vm, createElement)
        if (vm.$el) {
          diff(vm.$el, vnode)
        }
      })
    }

    // async call hooks
    requestAnimationFrame(function () {
      // created hook
      vm.created && vm.created()

      // $mount
      if (vm.$el) {
        vm.$mount(vm.$el)
      }
    })

    // test: return proxy
    if (typeof Proxy === 'function') {
      return new Proxy(vm, {
        set: function (vm, key, val) {
          vm[key] = val
          vm.$render()
        },
        get: function (vm, key) {
          vm.$render()
          return vm[key]
        }
      })
    }
  }


  var __createVnode = createVnode
  var __each = each
  VM.prototype = {
    constructor: VM,
    __createVnode: __createVnode,
    __each: __each,
    $mount: function (el) {
      this.$el = el

      // render first
      this.$render()

      // mounted hook
      this.mounted && this.mounted()
    }
  }
  VM.options = {
    directives: {}
  }