Skip to content

Latest commit

 

History

History
160 lines (119 loc) · 5.84 KB

19-props-and-normalizeProps.md

File metadata and controls

160 lines (119 loc) · 5.84 KB

props 和 normalizeProps

在过去的8篇文章里,我们绕过了 warn 函数。这篇中,我们回到 normalizeProps 函数中。自从我们上次看这个函数时,已经有一段时间了,那么让我们简单回顾下 normalizeProps

  • Vue 对象构造函数调用 this._init,参数为 options。
  • Vue.prototype._init 方法在 initMixin 函数中定义,参数为 options。
  • ._init 方法做了许多事,有一项是合并 options 选项。
  • 通过这两种方式之一合并 options:(1)如果 options._isComponent 为 true,._init 方法合并 options 是通过调用 initInternalComponent,传递的参数为 vmoptions;(2)如果 options._isComponent 不为 true,._init 方法合并 options 是通过调用 mergeOptions
  • mergeOptions 是一个把两个 options 合二为一的工具函数。
  • mergeOptions 函数中调用了 normalizeProps 函数。

上次我们停留在了这:

function normalizeProps (options: Object, vm: ?Component) {
  const props = options.props
  if (!props) return
  const res = {}
  let i, val, name
  if (Array.isArray(props)) {
    i = props.length
    while (i--) {
      val = props[i]
      if (typeof val === 'string') {
        name = camelize(val)
        res[name] = { type: null }
      } else if (process.env.NODE_ENV !== 'production') {
        warn('props must be strings when using array syntax.')
      }
    }
  } else if (isPlainObject(props)) {
    for (const key in props) {
      val = props[key]
      name = camelize(key)
      res[name] = isPlainObject(val)
        ? val
        : { type: val }
    }
  } else if (process.env.NODE_ENV !== 'production') {
    warn(
      `Invalid value for option "props": expected an Array or an Object, ` +
      `but got ${toRawType(props)}.`,
      vm
    )
  }
  options.props = res
}

但是如果你是个 Vue 新手,你可能会有这个疑问:“什么是 props”?在我们解答这个疑问之前,让我们先试着从源码中解释它。

props 是一个 options 上的属性:

const props = options.props

也可以是 options 对象中不存在 props 属性的情况:

if (!props) return

如果在 props 不存在的情况下,运行环境也没有抛出错误,说明 props 并不是必须的。

props 也可以是一个数组:

if (Array.isArray(props)) {

或者 props 也可以是一个对象:

} else if (isPlainObject(props)) {

但是如果 props 既不是对象也不是数组,会在开发环境中出现警告 warning

} else if (process.env.NODE_ENV !== 'production') {
  warn(
    `Invalid value for option "props": expected an Array or an Object, ` +
    `but got ${toRawType(props)}.`,
    vm
  )
}

如果 props 是数组,Vue 希望数组元素是字符串类型的。


规范化(Normalization)发生的情况有以下两种:

1. 对于数组格式的 props,遍历每一个元素,并转为驼峰式(camelized),把转后的字符作为 res 对象的一个键,并给 res 赋值为一个包含 type: null 的对象。

2. 对于对象格式的 props,res 对象是用 props 对象上的键(属性)填充的,如下:

} else if (isPlainObject(props)) {
  for (const key in props) {
    val = props[key]
    name = camelize(key)
    res[name] = isPlainObject(val)
      ? val
      : { type: val }
  }
}
  • 遍历 porps 上的属性:
for (var key in props) {
  • 遍历的时候,设置变量 val 的值为 props 的属性值:
val = props[key]
  • 遍历的时候,设置变量 name 的值为 props 属性名转为驼峰后的格式:
name = camelize(key)
  • 如果 props 的属性是个对象,设置 res 的一个属性,属性名就是 props 属性名转为驼峰后的格式,值根据 val 是不是对象来决定:
res[name] = isPlainObject(val)
  ? val
  : { type: val }

做所有有用的事情

如上,在规范化(Normalization)之后,normalizeProps 函数重置 options.propsres 变量(规范化后的结果)的值。

options.props = res

props 到底是什么?

现在我们已经学习了源码,我们进一步看下 Vue API:

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。

因此, options.props 是一个在以上定义下的一个注册元素。它是一个注册到组件的属性,这个属性可以接收数据作为自定义属性。

但是目前来说,我们没必要关心 props 的细节。我们只需要知道这个点:Vue 中存在一个函数,在正确的时机把相关字段转为驼峰式,并把 props 正确格式化,以此来规范 props 。

为了避免分散这篇文章,我们会跳到两个工具类函数的具体实现的学习:isPlainObjecttoRawType下一章我们会学习 isPlainObject