Vue-API之全局配置(个人向)

2,737 阅读4分钟

全局配置

Vue.config 是一个对象,包含 Vue 的全局配置。

  • 源码位置:util/config.js
  • 搜索config 可以找到其源码地址,其中声明了config的类型和默认参数 下面仅仅留下官方的几个配置项
export type Config = {
  // user
  optionMergeStrategies: { [key: string]:  Function }; //自定义合并策略的选项。
  silent: boolean; //关于日志和警告
  productionTip: boolean; //设置为 false 以阻止 vue 在启动时生成生产提示。
  performance: boolean;//设置为 true 以在浏览器开发工具的性能/时间线面板中启用对组件初始化、编译、渲染和打补丁的性能追踪。只适用于开发模式和支持 performance.mark API 的浏览器上。
  devtools: boolean; //配置是否允许 vue-devtools 检查代码。
  errorHandler: ?(err: Error, vm: Component, info: string) => void; //指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。
  warnHandler: ?(msg: string, vm: Component, trace: string) => void; //为 Vue 的运行时警告赋予一个自定义处理函数。注意这只会在开发者环境下生效,在生产环境下它会被忽略。
  ignoredElements: Array<string | RegExp>; //使 Vue 忽略在 Vue 之外的自定义元素 
  keyCodes: { [key: string]: number | Array<number> };//给 v-on 自定义键位别名

  // platform
  ..... 平台相关
  ......    
};
export default ({默认项}: Config))
  • 分析: 可以看出来整个config是进行了单独的整体的举例,然后配置完默认项后暴露出去,那么我们又是如何能够使用vue.confige.XXX 使用呢。

  • 源码地址 core/global-api/index.js
import config from '../config'
....
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)
....
}
  • 分析:,我们在这个文件中可以中看到,Vue在全局注入API 的时候将config注入.依然是用了Object.defineProperty()方法将其放在了Vue实例中。 综上我能感受到作为大框架对于各种功能的分散和聚合(用词不当,水平过低),是十分精炼的,组织结构清晰,明了。 那么接下来,我们简单看看vue提供的config暴露api大致都是如何工作的吧。

1、silent

  • 源码地址:core/util/debug.js
...
  warn = (msg, vm) => {
    const trace = vm ? generateComponentTrace(vm) : ''

    if (config.warnHandler) {
      config.warnHandler.call(null, msg, vm, trace)
    } else if (hasConsole && (!config.silent)) { //判断slinet
      console.error(`[Vue warn]: ${msg}${trace}`)
    }
  }

  tip = (msg, vm) => {
    if (hasConsole && (!config.silent)) {  // 判断slient
      console.warn(`[Vue tip]: ${msg}` + (
        vm ? generateComponentTrace(vm) : ''
      ))
    }
  }
...

  • 分析:我们可以看到再debug.js中vue对slient的使用,就是非常常规的判断,无需多说。

2、 optionMergeStrategies

  • 源码地址:core/util/option.js
...
 /**
 * Option overwriting strategies are functions that handle
 * how to merge a parent option value and a child option
 * value into the final value.
 */
const strats = config.optionMergeStrategies
... 做了老多事情
合并各种数据,数据,方法,watch等等

...

  • 分析: optionMergeStrategies主要用于 mixin 以及 Vue.extend() 方法时对于子组件和父组件如果有相同的属性(option),我们可以看到optionMergeStrategies的使用是在potion中,里面进行了各种合并,因为其中各种类型的合并策略都能拿出来细说,次此梳理,近是浅尝即止,顾不深究,以后有机会再去讨论,Vue方面更深刻的源码分析,还是先以数据驱动和响应式部分为主。

3、 devtools

  • 源码地址:core/observer/scheduler.js & core/util/env.js
/**
 * Flush both queues and run the watchers.
 */
function flushSchedulerQueue () {
    ...
    // devtool hook
  /* istanbul ignore if */
  if (devtools && config.devtools) {
    devtools.emit('flush')
  }
    ....
}
// detect devtools
export const devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__
  • 分析,可以看到devtools是声明或者定义是在env.js中其实就是window.VUE_DEVTOOLS_GLOBAL_HOOK 这个对象,如果你安装了这个工具,再控制台打印可以看到 {_buffer: Array(0), Vue: ƒ, _replayBuffer: ƒ, on: ƒ, once: ƒ, …}。那么其中你就可以看到再scheduler.js中是用的emit的方法, 我们只看对于vue的支持,这个工具的具体实现不考虑;,可以看到他的使用是在flushSchedulerQueue()这个方法中使用,这个方法在注释中就很清晰,而且这个方法也是vue响应式中很关键的方法,这里大致说一下, 再数据派发更新过程中Vue会遍历我们引入一个队列概念,这也是 Vue 在做派发更新的时候的⼀个优化的点,它并不会每次数据改 变都触发 watcher 的回调,⽽是把这些 watcher 先添加到⼀个队列⾥,然后在 nextTick 后执⾏flushSchedulerQueue 。其中先后进行了
  1. 队列排序,queue.sort((a, b) => a.id - b.id)
  2. 队列遍历在对 queue 排序后,接着就是要对它做遍历,拿到对应的 watcher ,执⾏ watcher.run()
  3. 状态恢复 执⾏ resetSchedulerState 函数,

大致如此,具体细节,又是很冗长繁琐,如有兴趣,可以看我的关于响应式的处理的后续的有关nextTick的部分。


4、 errorHandler

  • 源码位置 core/util/error.js
function globalHandleError (err, vm, info) {
  if (config.errorHandler) {
    try {
      return config.errorHandler.call(null, err, vm, info) //
    } catch (e) {
      // if the user intentionally throws the original error in the handler,
      // do not log it twice
      if (e !== err) {
        logError(e, null, 'config.errorHandler')
      }
    }
  }
  logError(err, vm, info)
}
  • 这个API其实看官方的文档就很好理解。

指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。

此处感觉没啥说的,,,,网上看到有分析的很多的,我就不细究了有兴趣可以 点击这里


5、warnHandler

  • 源码位置 core/util/error.js
 warn = (msg, vm) => {
    const trace = vm ? generateComponentTrace(vm) : ''

    if (config.warnHandler) {
      config.warnHandler.call(null, msg, vm, trace)
    } else if (hasConsole && (!config.silent)) {
      console.error(`[Vue warn]: ${msg}${trace}`)
    }
  }
  • 分析?感觉自己水平有限,实际使用几乎为零,没啥分析的。有兴趣看看这个文章,作者算是再Vue异常处理方面进行研究,这里

6、ignoredElements

  • 源码位置 core/dom/patch.js
  function isUnknownElement (vnode, inVPre) {
    return (
      !inVPre &&
      !vnode.ns &&
      !(
        config.ignoredElements.length &&
        config.ignoredElements.some(ignore => {
          return isRegExp(ignore)
            ? ignore.test(vnode.tag)
            : ignore === vnode.tag
        })
      ) &&
      config.isUnknownElement(vnode.tag)
    )
  }
  
  //creatElm函数
  function createElm (
  ...//
  ) {
\\...do more thing
    if (isDef(tag)) {
        ...//
        if (isUnknownElement(vnode, creatingElmInVPre)) {
          warn(
            'Unknown custom element: <' + tag + '> - did you ' +
            'register the component correctly? For recursive components, ' +
            'make sure to provide the "name" option.',
            vnode.context
          )
        }
      }
\\...do more thing 
}
  • 分析?官方文档提供的很好,

须使 Vue 忽略在 Vue 之外的自定义元素 (e.g. 使用了 Web Components APIs)。否则,它会假设你忘记注册全局组件或者拼错了组件名称,从而抛出一个关于 Unknown custom element 的警告。

代码也很清晰。可以看到报错点会出现在Vue进行数据驱动的核心方法creatElm中。,,关于数据驱动方面的内容可以看我的相关文章。


7、 keyCodes

  • 源码位置 core/instance/render-helpers/check-keycodes.js
function isKeyNotMatch<T> (expect: T | Array<T>, actual: T): boolean {
  if (Array.isArray(expect)) {
    return expect.indexOf(actual) === -1
  } else {
    return expect !== actual
  }
}

/**
 * Runtime helper for checking keyCodes from config.
 * exposed as Vue.prototype._k
 * passing in eventKeyName as last argument separately for backwards compat
 */
export function checkKeyCodes (
  eventKeyCode: number,
  key: string,
  builtInKeyCode?: number | Array<number>,
  eventKeyName?: string,
  builtInKeyName?: string | Array<string>
): ?boolean {
  const mappedKeyCode = config.keyCodes[key] || builtInKeyCode
  if (builtInKeyName && eventKeyName && !config.keyCodes[key]) {
    return isKeyNotMatch(builtInKeyName, eventKeyName)
  } else if (mappedKeyCode) {
    return isKeyNotMatch(mappedKeyCode, eventKeyCode)
  } else if (eventKeyName) {
    return hyphenate(eventKeyName) !== key
  }
}
  • 分析: 这个玩意,我专门实践了一下,其实就是自定义别名,看文档我当时有点懵逼,我改成了 如下
Vue.config.keyCodes = {
  v: 86,
  "media-play-pause": 86,
}
<input type="text" @keyup.media-play-pause="method($event)">

这里,你就会发现他就是定义自己的别名去对应专属的keyCode,对于上面的代码来说,就是这个method其实和V一样获取86的值就是了,个人感觉没啥用, 实现的话,就是源码方面的处理。随后又走了proxy,完成代理。不多赘述,这里说一下,有时候自己去试试,才能知道文档说的是个什么东东。。。。


8、 prformance

直接饮用官方说明

用法: 设置为 true 以在浏览器开发工具的性能/时间线面板中启用对组件初始化、编译、渲染和打补丁的性能追踪。只适用于开发模式和支持 performance.mark API 的浏览器上。

使用的话,需要安装一个插件,我一直安装不成功,不知道为啥,有一篇文章写得很好这里,可以查看。这个部分序性能优化,暂时我还没有详细去学习了解,此处留坑。。。回头补。


9、 productionTip

  • 源码地址:platforms/web/runtime/index.js
...
 if (process.env.NODE_ENV !== 'production' &&
      process.env.NODE_ENV !== 'test' &&
      config.productionTip !== false &&
      typeof console !== 'undefined'
    ) {
      console[console.info ? 'info' : 'log'](
        `You are running Vue in development mode.\n` +
        `Make sure to turn on production mode when deploying for production.\n` +
        `See more tips at https://vuejs.org/guide/deployment.html`
      )
...

如官方说明,无必要赘述。

用法: 设置为 false 以阻止 vue 在启动时生成生产提示。


  • 关于全局配置部分总结:
  1. 个人将全局配置部分算是浅显的走了一遍,说实话,其中部分内容我几乎都没有用过,而且确实这个梳理,更多像是,CV一下文档和源码代码。其中细节没有去深究,
  2. 整个Vue api 梳理的想法就是让我重新对Vue进行了解一下,毕竟Vue是个很大的项目,对于每个API不可能都去研究源码的细节,但求,有个概念,实操有个印象,也算是我对Vue,进一步了解。
  3. 关于源码部分,我也在同时学习,主要还是准备针对性的对他数据驱动和响应式的核心 处理部分进行学习了解,当然这个Api系列,也是在个人有精力同时研究有意义的情况下,回去深入了解的,如果精力不够或是从未涉及,我会找相对应我觉得不错的博客放出链接。
  4. 本文全是个人向内容,希望对看到的你,有所帮助,也是我对Vue学习的一个梳理吧。