• Vue初始化


    Vue上面的函数怎么来的

    vue的打包路径

    • 在web中使用的vue打包路径: npm run build 打包生成vue.js
    • 下面是依次引入:
      • src/platforms/web/entry-runtime-with-compiler.js
      • src/platforms/web/runtime/index.js
      • src/core/index.js
      • src/core/instance/index.js

    instance/index.js

    • 这个js文件就是Vue本身了
    • 首先这是一个构造函数, 然后在执行new的时候, 会执行一个this._init函数
    • 导出这个Vue之前, 都会挂载一些函数, 我们就来看看, 分别挂载了什么
    import { initMixin } from './init'
    import { stateMixin } from './state'
    import { renderMixin } from './render'
    import { eventsMixin } from './events'
    import { lifecycleMixin } from './lifecycle'
    import { warn } from '../util/index'
    
    function Vue (options) {
      if (process.env.NODE_ENV !== 'production' &&
        !(this instanceof Vue)
      ) {
        warn('Vue is a constructor and should be called with the `new` keyword')
      }
      this._init(options)
    }
    
    initMixin(Vue)
    stateMixin(Vue)
    eventsMixin(Vue)
    lifecycleMixin(Vue)
    renderMixin(Vue)
    
    export default Vue
    

    initMixin

    • 主要就是挂载了_init方法, 这是最关键的.

    stateMixin

    • $set
    • $delete
    • $watch

    eventsMixin

    • $on
    • $once
    • $off
    • emit

    lifecycleMixin

    • $_update
    • $forceUpdate
    • $destroy

    renderMixin

    • $nextTick
    • _render

    $mount

    • src/platforms/web/runtime/index.js进行挂载.
    • 这里引入了/src/core/instance/lifecycle.js中的mountComponent函数

    new vue都干了什么

    在这里就执行了一个_init函数

    总览函数, 逐个分析

      Vue.prototype._init = function (options?: Object) {
        const vm: Component = this
        // a uid
        vm._uid = uid++
    
        let startTag, endTag
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
          startTag = `vue-perf-start:${vm._uid}`
          endTag = `vue-perf-end:${vm._uid}`
          mark(startTag)
        }
    
        // a flag to avoid this being observed
        vm._isVue = true
        // merge options
        if (options && options._isComponent) {
          // optimize internal component instantiation
          // since dynamic options merging is pretty slow, and none of the
          // internal component options needs special treatment.
          initInternalComponent(vm, options)
        } else {
          vm.$options = mergeOptions(
            resolveConstructorOptions(vm.constructor),
            options || {},
            vm
          )
        }
        /* istanbul ignore else */
        if (process.env.NODE_ENV !== 'production') {
          initProxy(vm)
        } else {
          vm._renderProxy = vm
        }
        // expose real self
        vm._self = vm
        initLifecycle(vm)
        initEvents(vm)
        initRender(vm)
        callHook(vm, 'beforeCreate')
        initInjections(vm) // resolve injections before data/props
        initState(vm)
        initProvide(vm) // resolve provide after data/props
        callHook(vm, 'created')
    
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
          vm._name = formatComponentName(vm, false)
          mark(endTag)
          measure(`vue ${vm._name} init`, startTag, endTag)
        }
    
        if (vm.$options.el) {
          vm.$mount(vm.$options.el)
        }
      }
    

    initLifecycle

    • 初始化各种状态
    export function initLifecycle (vm: Component) {
      const options = vm.$options
    
      // locate first non-abstract parent
      let parent = options.parent
      if (parent && !options.abstract) {
        // 不断向下深复制所有的parent, 找到最终元素,
        while (parent.$options.abstract && parent.$parent) {
          parent = parent.$parent
        }
        parent.$children.push(vm)
      }
    
      // 确定该组件的状态, 初始化一些需要东西
      vm.$parent = parent
      vm.$root = parent ? parent.$root : vm
    
      vm.$children = []
      vm.$refs = {}
    
      vm._watcher = null
      vm._inactive = null
      vm._directInactive = false
      vm._isMounted = false
      vm._isDestroyed = false
      vm._isBeingDestroyed = false
    }
    

    initEvents

    • 初始化事件, 尤其是events, 还有一个listenners.
    export function initEvents (vm: Component) {
      vm._events = Object.create(null)
      vm._hasHookEvent = false
      // init parent attached events
      const listeners = vm.$options._parentListeners
      // 更新监听函数什么鬼呢?
      if (listeners) {
        updateComponentListeners(vm, listeners)
      }
    }
    

    initRender

    export function initRender (vm: Component) {
      vm._vnode = null // the root of the child tree
      vm._staticTrees = null // v-once cached trees
      const options = vm.$options
      const parentVnode = vm.$vnode = options._parentVnode // the placeholder node in parent tree
      const renderContext = parentVnode && parentVnode.context
      vm.$slots = resolveSlots(options._renderChildren, renderContext)
      vm.$scopedSlots = emptyObject
      // bind the createElement fn to this instance
      // so that we get proper render context inside it.
      // args order: tag, data, children, normalizationType, alwaysNormalize
      // internal version is used by render functions compiled from templates
      // 这里的createElement关键, 确定了我们需要页面上需要渲染的函数
      vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
      // normalization is always applied for the public version, used in
      // user-written render functions.
      vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
    
      // todo: 这里还没有搞太懂
      // $attrs & $listeners are exposed for easier HOC creation.
      // they need to be reactive so that HOCs using them are always updated
      const parentData = parentVnode && parentVnode.data
    
      /* istanbul ignore else */
      if (process.env.NODE_ENV !== 'production') {
        defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
          !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
        }, true)
        defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {
          !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
        }, true)
      } else {
        defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
        defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)
      }
    }
    

    这个时候, 调用钩子函数beforeCreate钩子

    initInjections

    • 这是一个高级用法, 在初识话data和prop之前, 来设置一些应该设置的值
    • 好吧, 还没有深入

    initState

    • 关键步骤:
      1. props
      2. methods
      3. data
      4. computed
      5. watcher
    
    export function initState (vm: Component) {
      vm._watchers = []
      const opts = vm.$options
      if (opts.props) initProps(vm, opts.props)
      if (opts.methods) initMethods(vm, opts.methods)
      if (opts.data) {
        initData(vm)
      } else {
        observe(vm._data = {}, true /* asRootData */)
      }
      if (opts.computed) initComputed(vm, opts.computed)
      if (opts.watch && opts.watch !== nativeWatch) {
        initWatch(vm, opts.watch)
      }
    }
    

    initProvide

    • 在初识完一系列的data, 和prop之后执行调用, 需要深入

    调用created函数

    mount

    • 如果存在options.el上面的el, 那么就会调用, mount函数
    • 这个函数指的就是在mountComponent函数.

    这时候, 调用beforeMount

    在mount中

    • 开始执行一系列的update和render函数
    • 执行结束后, 执行mounted, 这个时候, 这个组件就算渲染完成了.

    疑问

    • 如果在一个父组件中有两个子组件, 那么这个两个组件生命周期的执行顺序是什么?
    • 需要深入的还很多啊, 看了很多的文章, 杜宇Dep, Watcher, Observer的关系还是没这么清楚
    • 还有就是vue在初识化的过程中做了很多不知道的操作
  • 相关阅读:
    fiximulator
    Maven POM 模板[z]
    Sentinel 实战-控制台篇[z]
    Sentinel 实战-限流篇[z]
    RPC 框架
    如何手写实现简易的Dubbo[z]
    降级、熔断、限流[z]
    Transfix
    Memcached和Memcache安装(64位win7)[z]
    Oracle分区表例子
  • 原文地址:https://www.cnblogs.com/zhangrunhao/p/9996824.html
Copyright © 2020-2023  润新知