vue实例化

  1. initGlobalAPI(Vue) 初始化全局函数

为Vue 添加 config,util,set,delete,nextTick,observable,options,
use mixin extend 'component', directive filter 等属性和方法

  1. initMixin(Vue)

给Vue的原型添加 _init方法

  1. stateMixin(Vue)

给Vue的原型添加 $data,$props,$set,$delete,$watch

  1. eventsMixin(Vue)

给Vue的原型添加 $on, $emit, $off, $once 四个方法

  1. lifecycleMixin(Vue)

给 Vue的原型添加_update,$forceUpdate, $destroy

  1. renderMixin(Vue)
  // 给Vue的原型添加
  // target._o = markOnce
  // target._n = toNumber
  // target._s = toString
  // target._l = renderList
  // target._t = renderSlot
  // target._q = looseEqual
  // target._i = looseIndexOf
  // target._m = renderStatic
  // target._f = resolveFilter
  // target._k = checkKeyCodes
  // target._b = bindObjectProps
  // target._v = createTextVNode
  // target._e = createEmptyVNode
  // target._u = resolveScopedSlots
  // target._g = bindObjectListeners
  // target._d = bindDynamicKeys
  // target._p = prependModifier
  // 以及$nextTick, _render
  1. new Vue

初始化Vue,并且执行 this._init(options), initProxy(vm);

  1. initLifecycle(vm)

为vue实例添加属性 $parent $children $root $refs

  1. initEvents(vm)

为vue的实例 添加 _events _hasHookEvent,初始化组件通过@on监听的事件

  1. initRender(vm)

为实例添加 $slots .$scopedSlots _c $createElement $attrs $listeners
将$attrs $listeners响应式处理, 不做依赖收集

  1. callHook(vm, 'beforeCreate')

执行beforeCreate钩子

  1. initInjections(vm)
    处理提供的 inject ,inject不做响应式处理
  2. initState(vm)

初始化 props methods data computed watch, 并做响应式处理

  1. initProps(vm, opts.props)
  2. for (var key in propsOptions) loop( key ); ,遍历初始化传入的props
    1. var value = validateProp(key, propsOptions, propsData, vm);
    2. validateProp对props的的属性的值进行observe,比如 props: {
      fatherProp: {
      type : Object,
      default: () => ({
      testprop: '测试props'
      })
      }
      }validateProp函数会对 {testprop: '测试props'}进行observe
      2. loop函数内部调用defineReactive(props, key, value)
    3. defineReactive函数内部调用observe(val);递归观测
  3. proxy(vm, _props, key),将_props 的属性代理到 vm实例上
  4. initMethods(vm, opts.methods)
  5. vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
  6. initData(vm)
  7. observe(data, true /* asRootData */)
    1. ob = new Observer(value)
    2. this.walk(value)
    3. defineReactive(obj, keys[i])
  8. initComputed(vm, opts.computed)
  9. initWatch(vm, opts.watch)
  1. initProvide(vm)

给 vue实例添加 _provided属性,初始化组件的provide

  1. callHook(vm, 'created')

调用 created钩子

  1. vm.$mount(vm.$options.el)

开始执行挂载

  • 调用compileToFunctions生成编译render函数
  // src/compiler/to-function.js
  function createFunction (code, errors) {
    try {
      return new Function(code)
    } catch (err) {
      errors.push({ err, code })
      return noop
    }
  }
  export function createCompileToFunctionFn (compile) {
    return function compileToFunctions (
      template,
      options,
      vm
    ){
      // 对模板进行编译
      const compiled = compile(template, options)
      res.render = createFunction(compiled.render, fnGenErrors)
      res.staticRenderFns = compiled.staticRenderFns.map(code => {
        return createFunction(code, fnGenErrors)
      })
      return (cache[key] = res)
    }
  }
  // src/compiler/create-compiler.js
  export function createCompilerCreator (baseCompile) {
    return function createCompiler (baseOptions) {
      function compile (
        template,
        options
      ){
        const compiled = baseCompile(template.trim(), finalOptions)
        return compiled
      }
      return {
        compile,
        compileToFunctions: createCompileToFunctionFn(compile)
      }
    }
  }
// src/compiler/index.js
import { createCompilerCreator } from './create-compiler'
// `createCompilerCreator` allows creating compilers that use alternative
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
// Here we just export a default compiler using the default parts.
export const createCompiler = createCompilerCreator(function baseCompile (
  template: string,
  options: CompilerOptions
) {
  const ast = parse(template.trim(), options)
  if (options.optimize !== false) {
    optimize(ast, options)
  }
  const code = generate(ast, options)
  return {
    ast,
    render: code.render,
    staticRenderFns: code.staticRenderFns
  }
})
// src/platforms/web/compiler/index.js

import { createCompiler } from 'compiler/index'
const { compile, compileToFunctions } = createCompiler(baseOptions)
export { compile, compileToFunctions }

// src/platforms/web/entry-runtime-with-compiler.js
import { compileToFunctions } from './compiler/index'
const { render, staticRenderFns } = compileToFunctions(template, {
  outputSourceRange: process.env.NODE_ENV !== 'production',
  shouldDecodeNewlines,
  shouldDecodeNewlinesForHref,
  delimiters: options.delimiters,
  comments: options.comments
}, this)
// ref.render 此时已经成了 new Function('with(this){}')
var render = ref.render;
- 调用function compile (){}
- 调用function baseCompile(){}
  - var ast = parse(template.trim(), options)
  - 调用generate(ast, options);
  - 调用genElement(ast, state);
    - genChildren()
      - (children.map(function (c) { return gen(c, state); })
        - gen 函数就是 genNode,递归调用genElement生成渲染函数
        ```js
         function genNode (node, state) {
          if (node.type === 1) {
            return genElement(node, state)
          } else if (node.type === 3 && node.isComment) {
            return genComment(node)
          } else {
            return genText(node)
          }
        }
- 调用genElement返回【code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")";】
- return {
    render: ("with(this){return " + code + "}"),
    staticRenderFns: state.staticRenderFns
  }
  1. 调用mount.call(this, el, hydrating) 实际调用Vue.prototype.$mount
  2. mountComponent(this, el, hydrating),开始挂载组件
  • callHook(vm, 'beforeMount'); 调用 beforeMount钩子
  • updateComponent = function () { vm._update(vm._render(), hydrating); }; 定义updateComponent函数,等待调用
  1. 调用new Watcher()
new Watcher(vm, updateComponent, noop, {
  before: function before () {
    if (vm._isMounted && !vm._isDestroyed) {
      callHook(vm, 'beforeUpdate');
    }
  }
}, true /* isRenderWatcher */);
  • this.get()
  • this.getter.call(vm, vm);
  • updateComponent()
  • vm._render()
  • render.call(vm._renderProxy, vm.$createElement);
(function anonymous() {
  with(this) {
    return _c('div', {
      attrs: {
        "id": "app"
      }
    }, [_c('h1', [_v(_s(fatherData))]), _v(" "), _c('h2', [_v(_s(fatherProp3))]), _v(" "), _c('test-test', {
      on: {
        "xxxx": xxxx
      }
    })], 1)
  }
})
  1. render函数内部获取了props和data定义的数据,所以调用了reactiveGetter(),开始依赖收集
  • dep.depend();
Dep.prototype.depend = function depend () {
  if (Dep.target) {
    // this 是dep实例
    // Dep.target 是watcher实例
    Dep.target.addDep(this);
  }
};
  • Dep.target.addDep(this); this是dep实例
  Watcher.prototype.addDep = function addDep (dep) {
    var id = dep.id;
    // this 是watcher实例
    if (!this.newDepIds.has(id)) {
      this.newDepIds.add(id);
      this.newDeps.push(dep);
      if (!this.depIds.has(id)) {
        // 依赖收集
        dep.addSub(this);
      }
    }
  };
  1. 调用vm._update(vm._render(), hydrating);
// 第一次渲染没有prevVnode, 直接移除旧的
  if (!prevVnode) {
    // initial render
    vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
  } else {
    // updates
    vm.$el = vm.__patch__(prevVnode, vnode);
  }
  • patch (oldVnode, vnode, hydrating, removeOnly){}
  • createElm()
 createElm(
    vnode,
    insertedVnodeQueue,
    // extremely rare edge case: do not insert if old element is in a
    // leaving transition. Only happens when combining transition +
    // keep-alive + HOCs. (#4590)
    oldElm._leaveCb ? null : parentElm,
    nodeOps.nextSibling(oldElm)
  );
  • setScope(vnode); 为scoped Css设置data-v-5132e20a 唯一id

  • createChildren( (vnode, children, insertedVnodeQueue))

    • checkDuplicateKeys(children); 当元素设置key的时候,比如for循环
    • 遍历生成children
      for (var i = 0; i < children.length; ++i) {
        createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i);
      }
    
  1. 如果发现了自定义组件则调用 createComponentInstanceForVnode()
  • 重复执行步骤16 - 21
  1. removeVnodes([oldVnode], 0, 0); 移除老的node节点
posted @ 2021-03-19 18:00  Samsara315  阅读(20)  评论(0编辑  收藏  举报