当前位置: 首页 > news >正文

【根据源码分析Vue 组件中 props的实现原理 】

根据源码分析Vue 组件中 props的实现原理

      • 整体功能概述
      • 代码详细解释
        • 1. 导入模块和类型定义
        • 2. `validateProp` 函数
        • 3. `getPropDefaultValue` 函数
        • 4. `assertProp` 函数
        • 5. `assertType` 函数
        • 6. 其他辅助函数
      • 实现原理总结

整体功能概述

源码实现了一系列用于验证和处理组件 props 的工具函数,主要包括:

  • validateProp:验证单个 prop 的值,并处理默认值和类型转换。
  • getPropDefaultValue:获取 prop 的默认值。
  • assertProp:断言 prop 是否有效。
  • assertType:检查值的类型是否符合预期。
  • 其他辅助函数,如 getTypeisSameType 等。

代码详细解释

1. 导入模块和类型定义
/* @flow */

import { warn } from './debug'
import { observe, toggleObserving, shouldObserve } from '../observer/index'
import {
  hasOwn,
  isObject,
  toRawType,
  hyphenate,
  capitalize,
  isPlainObject
} from 'shared/util'

type PropOptions = {
  type: Function | Array<Function> | null,
  default: any,
  required: ?boolean,
  validator: ?Function
};
  • /* @flow */:表示该文件使用 Flow 进行静态类型检查。
  • 导入了多个工具函数和模块,用于调试警告、响应式观察和一些通用工具方法。
  • PropOptions 定义了 prop 的选项类型,包括 type(类型)、default(默认值)、required(是否必需)和 validator(自定义验证函数)。
2. validateProp 函数
export function validateProp (
  key: string,
  propOptions: Object,
  propsData: Object,
  vm?: Component
): any {
  const prop = propOptions[key]
  const absent = !hasOwn(propsData, key)
  let value = propsData[key]
  // boolean casting
  const booleanIndex = getTypeIndex(Boolean, prop.type)
  if (booleanIndex > -1) {
    if (absent && !hasOwn(prop, 'default')) {
      value = false
    } else if (value === '' || value === hyphenate(key)) {
      // only cast empty string / same name to boolean if
      // boolean has higher priority
      const stringIndex = getTypeIndex(String, prop.type)
      if (stringIndex < 0 || booleanIndex < stringIndex) {
        value = true
      }
    }
  }
  // check default value
  if (value === undefined) {
    value = getPropDefaultValue(vm, prop, key)
    // since the default value is a fresh copy,
    // make sure to observe it.
    const prevShouldObserve = shouldObserve
    toggleObserving(true)
    observe(value)
    toggleObserving(prevShouldObserve)
  }
  if (
    process.env.NODE_ENV !== 'production' &&
    // skip validation for weex recycle-list child component props
    !(__WEEX__ && isObject(value) && ('@binding' in value))
  ) {
    assertProp(prop, key, value, vm, absent)
  }
  return value
}
  • 功能:验证单个 prop 的值,并处理默认值和类型转换。
  • 参数
    • keyprop 的名称。
    • propOptionsprop 的选项对象。
    • propsData:传入的 props 数据。
    • vm:可选的 Vue 实例。
  • 步骤
    1. 获取 prop 的选项和值,并检查是否缺失。
    2. 处理布尔类型的 prop,如果缺失且没有默认值,将其设为 false;如果值为空字符串或与 prop 名称相同,且布尔类型优先级更高,则将其设为 true
    3. 如果值为 undefined,则获取默认值,并确保默认值是响应式的。
    4. 在开发环境下,调用 assertProp 函数进行 prop 验证。
    5. 返回验证后的值。
3. getPropDefaultValue 函数
function getPropDefaultValue (vm: ?Component, prop: PropOptions, key: string): any {
  // no default, return undefined
  if (!hasOwn(prop, 'default')) {
    return undefined
  }
  const def = prop.default
  // warn against non-factory defaults for Object & Array
  if (process.env.NODE_ENV !== 'production' && isObject(def)) {
    warn(
      'Invalid default value for prop "' + key + '": ' +
      'Props with type Object/Array must use a factory function ' +
      'to return the default value.',
      vm
    )
  }
  // the raw prop value was also undefined from previous render,
  // return previous default value to avoid unnecessary watcher trigger
  if (vm && vm.$options.propsData &&
    vm.$options.propsData[key] === undefined &&
    vm._props[key] !== undefined
  ) {
    return vm._props[key]
  }
  // call factory function for non-Function types
  // a value is Function if its prototype is function even across different execution context
  return typeof def === 'function' && getType(prop.type) !== 'Function'
    ? def.call(vm)
    : def
}
  • 功能:获取 prop 的默认值。
  • 参数
    • vm:可选的 Vue 实例。
    • propprop 的选项对象。
    • keyprop 的名称。
  • 步骤
    1. 如果 prop 没有默认值,返回 undefined
    2. 在开发环境下,如果默认值是对象或数组且不是工厂函数,发出警告。
    3. 如果上一次渲染时 prop 的值也是 undefined,返回上一次的默认值,以避免不必要的监听器触发。
    4. 如果默认值是函数且 prop 类型不是 Function,调用该函数并返回结果;否则,直接返回默认值。
4. assertProp 函数
function assertProp (
  prop: PropOptions,
  name: string,
  value: any,
  vm: ?Component,
  absent: boolean
) {
  if (prop.required && absent) {
    warn(
      'Missing required prop: "' + name + '"',
      vm
    )
    return
  }
  if (value == null && !prop.required) {
    return
  }
  let type = prop.type
  let valid = !type || type === true
  const expectedTypes = []
  if (type) {
    if (!Array.isArray(type)) {
      type = [type]
    }
    for (let i = 0; i < type.length && !valid; i++) {
      const assertedType = assertType(value, type[i])
      expectedTypes.push(assertedType.expectedType || '')
      valid = assertedType.valid
    }
  }

  if (!valid) {
    warn(
      getInvalidTypeMessage(name, value, expectedTypes),
      vm
    )
    return
  }
  const validator = prop.validator
  if (validator) {
    if (!validator(value)) {
      warn(
        'Invalid prop: custom validator check failed for prop "' + name + '".',
        vm
      )
    }
  }
}
  • 功能:断言 prop 是否有效。
  • 参数
    • propprop 的选项对象。
    • nameprop 的名称。
    • valueprop 的值。
    • vm:可选的 Vue 实例。
    • absent:表示 prop 是否缺失。
  • 步骤
    1. 如果 prop 是必需的但缺失,发出警告并返回。
    2. 如果 prop 不是必需的且值为 nullundefined,直接返回。
    3. 检查 prop 的类型是否符合预期,如果不符合,发出警告。
    4. 如果 prop 有自定义验证函数,调用该函数进行验证,如果验证失败,发出警告。
5. assertType 函数
const simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/

function assertType (value: any, type: Function): {
  valid: boolean;
  expectedType: string;
} {
  let valid
  const expectedType = getType(type)
  if (simpleCheckRE.test(expectedType)) {
    const t = typeof value
    valid = t === expectedType.toLowerCase()
    // for primitive wrapper objects
    if (!valid && t === 'object') {
      valid = value instanceof type
    }
  } else if (expectedType === 'Object') {
    valid = isPlainObject(value)
  } else if (expectedType === 'Array') {
    valid = Array.isArray(value)
  } else {
    valid = value instanceof type
  }
  return {
    valid,
    expectedType
  }
}
  • 功能:检查值的类型是否符合预期。
  • 参数
    • value:要检查的值。
    • type:预期的类型。
  • 步骤
    1. 获取预期类型的名称。
    2. 如果预期类型是简单类型(StringNumberBooleanFunctionSymbol),检查值的类型是否匹配;如果不匹配且值是对象,检查是否是该类型的实例。
    3. 如果预期类型是 Object,检查值是否是普通对象。
    4. 如果预期类型是 Array,检查值是否是数组。
    5. 对于其他类型,检查值是否是该类型的实例。
    6. 返回检查结果和预期类型名称。
6. 其他辅助函数
function getType (fn) {
  const match = fn && fn.toString().match(/^\s*function (\w+)/)
  return match ? match[1] : ''
}

function isSameType (a, b) {
  return getType(a) === getType(b)
}

function getTypeIndex (type, expectedTypes): number {
  if (!Array.isArray(expectedTypes)) {
    return isSameType(expectedTypes, type) ? 0 : -1
  }
  for (let i = 0, len = expectedTypes.length; i < len; i++) {
    if (isSameType(expectedTypes[i], type)) {
      return i
    }
  }
  return -1
}

function getInvalidTypeMessage (name, value, expectedTypes) {
  let message = `Invalid prop: type check failed for prop "${name}".` +
    ` Expected ${expectedTypes.map(capitalize).join(', ')}`
  const expectedType = expectedTypes[0]
  const receivedType = toRawType(value)
  const expectedValue = styleValue(value, expectedType)
  const receivedValue = styleValue(value, receivedType)
  // check if we need to specify expected value
  if (expectedTypes.length === 1 &&
      isExplicable(expectedType) &&
      !isBoolean(expectedType, receivedType)) {
    message += ` with value ${expectedValue}`
  }
  message += `, got ${receivedType} `
  // check if we need to specify received value
  if (isExplicable(receivedType)) {
    message += `with value ${receivedValue}.`
  }
  return message
}

function styleValue (value, type) {
  if (type === 'String') {
    return `"${value}"`
  } else if (type === 'Number') {
    return `${Number(value)}`
  } else {
    return `${value}`
  }
}

function isExplicable (value) {
  const explicitTypes = ['string', 'number', 'boolean']
  return explicitTypes.some(elem => value.toLowerCase() === elem)
}

function isBoolean (...args) {
  return args.some(elem => elem.toLowerCase() === 'boolean')
}
  • getType:通过函数的字符串表示获取类型名称。
  • isSameType:检查两个值的类型是否相同。
  • getTypeIndex:获取类型在预期类型数组中的索引。
  • getInvalidTypeMessage:生成类型检查失败的错误信息。
  • styleValue:根据类型格式化值。
  • isExplicable:检查值的类型是否可明确表示。
  • isBoolean:检查值的类型是否为布尔类型。

实现原理总结

  • 验证流程 :当组件接收到 props 时, validateProp 函数会对每个 prop 进行验证。首先进行布尔类型转换,然后处理默认值,最后在非生产环境下进行验证。
  • 类型检查assertType 函数负责检查值的类型是否符合要求,根据不同的类型使用不同的检查方法。
  • 默认值处理getPropDefaultValue 函数负责获取 prop 的默认值,并处理非工厂函数的默认值警告。
  • 自定义验证 :如果 prop 定义了自定义验证函数,则在 assertProp 函数中调用该函数进行验证。

通过这些函数的协作,Vue 实现了对 props 的验证和处理,确保组件接收到的 props 符合定义要求。

相关文章:

  • TA学习之路——1.5纹理基础
  • 人工智能基础知识详解:从概念到前沿技术与应用
  • RAG中构建个人知识库
  • 第3课:MCP协议接口定义与开发实践
  • 医学图像分割效率大幅提升!U-Net架构升级,助力精度提升5%!
  • iPaaS集成平台使用的最佳实践:开发、测试和生产部署
  • rhcsa第三次作业
  • 解释 Git 的基本概念和使用方式
  • ZLMediaKit部署与配置
  • 【嵌入式系统设计师】知识点:第4章 嵌入式系统软件基础知识
  • 刷题(删除倒数第N个节点、搜索插入位置、二进制求和、求x平方根、爬楼梯)
  • 如何在 Windows 11 上查找计算机的 IP 地址?
  • 理解 Rust 中的 String 分配机制
  • 【Vue-组件】学习笔记
  • AI烘焙大赛中的算法:理解PPO、GRPO与DPO的罪简单的方式
  • NVR接入录像回放平台用EasyCVR打造地下车库安防:大型商居安全优选方案
  • Windows 图形显示驱动开发-WDDM 2.0功能_重排范围
  • 阿里云大模型训练与推理开发
  • 关于点卷积
  • 利用Ollama对AI大模型进行攻击
  • 佛山做网站需要多少钱/武汉seo优化顾问
  • 公司网站模板最新/深圳做网站公司
  • 秦皇岛网站开发费用/广州百度推广排名优化
  • 网站建设需要哪些工作室/重庆百度推广
  • 怎么快速做网站/全网整合营销推广方案
  • 网站的版式/最近的新闻有哪些