美文网首页
vue源码分析(四)解密new Vue()之前做了哪些不为人知工

vue源码分析(四)解密new Vue()之前做了哪些不为人知工

作者: vue爱好者 | 来源:发表于2020-03-19 09:56 被阅读0次

    上一篇我们说过了vue实例化之前会调用 initGlobalAPI(Vue) 方法,那我们先看看一下定义initGlobalAPI 方法的路径 “src/core/global-api/index.js”。

    打开文件可以看到上面导入了很多的对象,但基本都是定义函数的,没有涉及到执行,我们可以先不看,最主要的我们来看一下这个文件。

    "import builtInComponents from '../components/index'"
    

    代码如下:

    import KeepAlive from './keep-alive'
    
    export default {
      KeepAlive
    }
    

    然后我们再打开 “src/core/components/keep-alive.js” 代码如下:

    /* @flow */
    
    import { isRegExp, remove } from 'shared/util'
    import { getFirstComponentChild } from 'core/vdom/helpers/index'
    
    type VNodeCache = { [key: string]: ?VNode };
    
    ......为了不增大篇幅,省略部分代码(大家可自行查看)
    
    export default {
      name: 'keep-alive',
      abstract: true,
    
      props: {
        include: patternTypes,
        exclude: patternTypes,
        max: [String, Number]
      },
    
      created () {
        this.cache = Object.create(null)
        this.keys = []
      },
    
      destroyed () {
        for (const key in this.cache) {
          pruneCacheEntry(this.cache, key, this.keys)
        }
      },
    
      mounted () {
        this.$watch('include', val => {
          pruneCache(this, name => matches(val, name))
        })
        this.$watch('exclude', val => {
          pruneCache(this, name => !matches(val, name))
        })
      },
    
      render () {
        const slot = this.$slots.default
        const vnode: VNode = getFirstComponentChild(slot)
        const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
        if (componentOptions) {
          // check pattern
          const name: ?string = getComponentName(componentOptions)
          const { include, exclude } = this
          if (
            // not included
            (include && (!name || !matches(include, name))) ||
            // excluded
            (exclude && name && matches(exclude, name))
          ) {
            return vnode
          }
    
          const { cache, keys } = this
          const key: ?string = vnode.key == null
            // same constructor may get registered as different local components
            // so cid alone is not enough (#3269)
            ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
            : vnode.key
          if (cache[key]) {
            vnode.componentInstance = cache[key].componentInstance
            // make current key freshest
            remove(keys, key)
            keys.push(key)
          } else {
            cache[key] = vnode
            keys.push(key)
            // prune oldest entry
            if (this.max && keys.length > parseInt(this.max)) {
              pruneCacheEntry(cache, keys[0], keys, this._vnode)
            }
          }
    
          vnode.data.keepAlive = true
        }
        return vnode || (slot && slot[0])
      }
    }
    

    通过以上代码我们看到导出了一个对象 “keep-alive”,对于这个对象大家应该比较熟悉了,这是vue的一个内置组件,主要用来缓存路由的。这个我们后期再分享具体的代码,我们还是接着看 "initGlobalAPI(vue)"的具体代码:

    export function initGlobalAPI (Vue: GlobalAPI) {
      // config
      const configDef = {}
      configDef.get = () => config
      if (process.env.NODE_ENV !== 'production') {
        configDef.set = () => {
          warn(
            'Do not replace the Vue.config object, set individual fields instead.'
          )
        }
      }
      Object.defineProperty(Vue, 'config', configDef)
    
      // exposed util methods.
      // NOTE: these are not considered part of the public API - avoid relying on
      // them unless you are aware of the risk.
      Vue.util = {
        warn,
        extend,
        mergeOptions,
        defineReactive
      }
    
      Vue.set = set
      Vue.delete = del
      Vue.nextTick = nextTick
    
      // 2.6 explicit observable API
      Vue.observable = <T>(obj: T): T => {
        observe(obj)
        return obj
      }
    
      Vue.options = Object.create(null)
      ASSET_TYPES.forEach(type => {
        Vue.options[type + 's'] = Object.create(null)
      })
    
      // this is used to identify the "base" constructor to extend all plain-object
      // components with in Weex's multi-instance scenarios.
      Vue.options._base = Vue
    
      extend(Vue.options.components, builtInComponents)
    
      initUse(Vue)
      initMixin(Vue)
      initExtend(Vue)
      initAssetRegisters(Vue)
    }
    

    可以看到对 “config”属性进行了一个拦截。

    “Object.defineProperty(Vue, 'config', configDef)”
    

    然后给vue注册了 “set”、“delete”、“nextTick”三个属性,和我们在第三讲说的在vue原型对象上面挂载了“ set”、“delete”是一样的,都是指向同一个函数,正如官方说的 “这是全局 Vue.set 的别名”。

    Vue.set = set
    Vue.delete = del
    Vue.nextTick = nextTick
    

    紧接着就是给vue添加了一个观察者,然后给 Vue.options对象添加了三个属性 directives、filters、components。

    注释:ASSET_TYPES = ['component','directive','filter']

    然后就是让“components”属性继承了 builtInComponents。

    接下来可以清楚的看到调用了如下4个函数:

    initUse(Vue) // 在vue实例上挂载use方法(此方法用来加载插件)

    initMixin(Vue) // 在vue实例上挂载mixin方法

    initExtend(Vue) // 在vue实例上挂载extend方法

    initAssetRegisters(Vue) // 在vue实例上挂载directives、filters、components

    到这一步vue的准备工作基本 做完了,接下来我们看看new Vue()之后做了哪些不为人知的工作。

    相关文章

      网友评论

          本文标题:vue源码分析(四)解密new Vue()之前做了哪些不为人知工

          本文链接:https://www.haomeiwen.com/subject/svjkyhtx.html