zoukankan      html  css  js  c++  java
  • 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在初识化的过程中做了很多不知道的操作
  • 相关阅读:
    CODING x 百果园 _ 水果零售龙头迈出 DevOps 体系建设第一步
    Nocalhost 亮相 CD Foundation 国内首届 Meetup,Keith Chan 将出席致辞
    做云原生时代标准化工具,实现高效云上研发工作流
    打造数字化软件工厂 —— 一站式 DevOps 平台全景解读
    WePack —— 助力企业渐进式 DevOps 转型
    CODING Compass —— 打造行云流水般的软件工厂
    Nocalhost —— 让云原生开发回归原始而又简单
    CODING 代码资产安全系列之 —— 构建全链路安全能力,守护代码资产安全
    Nocalhost:云原生开发新体验
    使用 Nocalhost 开发 Kubernetes 中的 APISIX Ingress Controller
  • 原文地址:https://www.cnblogs.com/zhangrunhao/p/9996824.html
Copyright © 2011-2022 走看看