DOMProperty

DOMProperty模块用于加载节点属性插件,最终影响DOMPropertyOperation模块对节点属性的添加移除处理。

 

'use strict';

var _prodInvariant = require('./reactProdInvariant');
var invariant = require('fbjs/lib/invariant');

// 获取是否以node[propName]=value方式添加属性,或属性值处理方式
function checkMask(value, bitmask) {
  return (value & bitmask) === bitmask;
}

var DOMPropertyInjection = {
  MUST_USE_PROPERTY: 0x1,// 0x 16位 以node[propName]=value方式添加属性
  HAS_BOOLEAN_VALUE: 0x4,// 过滤否值
  HAS_NUMERIC_VALUE: 0x8,// 过滤非数值型
  HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8,// 过滤非正数型
  HAS_OVERLOADED_BOOLEAN_VALUE: 0x20,// 过滤false

  /**节点属性插件的写法,即含有的属性:
   *
   * isCustomAttribute: 函数,返回真值,将添加到节点的属性,如HTMLDOMPropertyConfig模块的data-、aria-
   *
   * Properties: 设定属性值类型处理方式的集合,如某属性值为0x4,否值将不会添加为节点的属性
   *
   * DOMAttributeNames: 键值对存储属性名,以字符串形式拼接属性名及其值时使用
   *
   * DOMAttributeNamespaces: 键值对约定属性命名空间的集合
   *
   * DOMPropertyNames: Properties中属性设为0x1,即MUST_USE_PROPERTY时,node[propName]=value方式添加属性的属性名集合
   *
   * DOMMutationMethods: 存储设定属性值的方法集,如{propName:(node,value)=>{}}
   */
  // 加载节点属性插件,为DOMProperty.properties、DOMProperty._isCustomAttributeFunctions注入内容
  injectDOMPropertyConfig: function (domPropertyConfig) {
    var Injection = DOMPropertyInjection;

    // 设定属性值类型处理方式的集合,如某属性值为0x4,否值将不会添加为节点的属性
    var Properties = domPropertyConfig.Properties || {};

    // 约定属性命名空间的集合
    var DOMAttributeNamespaces = domPropertyConfig.DOMAttributeNamespaces || {};

    // react属性名到浏览器节点属性名的映射,如{className:"class"}
    var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};

    // 存储属性的命名空间
    var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};

    // 存储设定属性值的方法集,如{propName:(node,value)=>{}}
    var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};

    // 自定义属性校验,通过则将添加到节点的相应属性上,如HTMLDOMPropertyConfig模块的data-、aria-
    if (domPropertyConfig.isCustomAttribute) {
      DOMProperty._isCustomAttributeFunctions.push(domPropertyConfig.isCustomAttribute);
    }

    for (var propName in Properties) {
      // 同名属性不能加载两次,也即各节点属性插件的属性名不能相冲
      !!DOMProperty.properties.hasOwnProperty(propName) ? 
        process.env.NODE_ENV !== 'production' ? 
          invariant(false, 'injectDOMPropertyConfig(...):' 
            + ' You\'re trying to inject DOM property \'%s\' which has already been injected.' 
            + ' You may be accidentally injecting the same DOM property config twice,' 
            + ' or you may be injecting two configs that have conflicting property names.', propName) 
          : _prodInvariant('48', propName) : void 0;

      var lowerCased = propName.toLowerCase();

      // 节点属性插件中,propName指代属性名,Properties[propName]约定类型
      // Properties[propName]同DOMPropertyInjection.HAS_NUMERIC_VALUE等属性作按位与比较
      // 两者等值时,属性值须设为DOMPropertyInjection.HAS_NUMERIC_VALUE等属性的字面类型
      // 即DOMPropertyInjection.HAS_NUMERIC_VALUE要求节点的属性为数值
      var propConfig = Properties[propName];

      var propertyInfo = {
        // 拼接字符串方式添加节点属性时,作为属性名
        attributeName: lowerCased,

        // 属性的命名空间,node.setAttributeNS(namespace,attr,value)添加属性;初始化为null
        attributeNamespace: null,

        // propertyInfo.mustUseProperty为真值时,node[propertyInfo[propertyName]]设置节点的属性时作为节点的属性名
        propertyName: propName,

        // 设置属性值的方法,(node,value)=>{}形式;初始化为null
        mutationMethod: null,

        // 为真值时,以node[propertyInfo[propertyName]]设置节点的属性,而非setAttribute方法
        // 处理ie8、9setAttribute方法将属性值转化为字符串`[object]`的兼容性问题
        mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),

        // 用于设定节点属性值的类型,如hasNumericValue属性为真值,属性值得类型即为数值型
        hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE),
        hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE),
        hasPositiveNumericValue: checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE),
        hasOverloadedBooleanValue: checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE)
      };

      // 属性值的类型设定相冲,如不能既是布尔型,又是数值型
      !(propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue + 
        propertyInfo.hasOverloadedBooleanValue <= 1) ? 
          process.env.NODE_ENV !== 'production' ? 
            invariant(false, 'DOMProperty: Value can be one of boolean, overloaded boolean,' 
              + ' or numeric value, but not a combination: %s', propName) : 
            _prodInvariant('50', propName) : 
          void 0;

      if (process.env.NODE_ENV !== 'production') {
        DOMProperty.getPossibleStandardName[lowerCased] = propName;
      }

      // 节点属性插件的DOMAttributeNames属性是react属性名到浏览器节点属性名的映射,如className映射为class
      // 以字符串形式拼接属性名及其值时使用
      if (DOMAttributeNames.hasOwnProperty(propName)) {
        var attributeName = DOMAttributeNames[propName];
        propertyInfo.attributeName = attributeName;
        if (process.env.NODE_ENV !== 'production') {
          DOMProperty.getPossibleStandardName[attributeName] = propName;
        }
      }

      // 提取节点属性插件DOMAttributeNamespaces的命名空间
      if (DOMAttributeNamespaces.hasOwnProperty(propName)) {
        propertyInfo.attributeNamespace = DOMAttributeNamespaces[propName];
      }

      // DOMPropertyNames存放propertyInfo.mustUseProperty为真值时可添加的属性名集合
      if (DOMPropertyNames.hasOwnProperty(propName)) {
        propertyInfo.propertyName = DOMPropertyNames[propName];
      }

      // propertyInfo.mutationMethod设置属性值的方法,(node,value)=>{}形式
      if (DOMMutationMethods.hasOwnProperty(propName)) {
        propertyInfo.mutationMethod = DOMMutationMethods[propName];
      }

      DOMProperty.properties[propName] = propertyInfo;
    }
  }
};

var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';

var DOMProperty = {

  ID_ATTRIBUTE_NAME: 'data-reactid',
  ROOT_ATTRIBUTE_NAME: 'data-reactroot',

  // 用于校验属性名
  ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR,
  ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040',

  /**设定属性名添加或移除方式

   * attributeName: 拼接字符串方式

   * attributeNamespace: 属性的命名空间

   * propertyName: mustUseProperty为真值时,node[propName]方式添加或移除属性时,作为propName

   * mutationMethod: 设置属性值的方法,(node,value)=>{}形式,优先级最高

   * mustUseProperty: 是否以node[propertyInfo[propertyName]]设置节点的属性,而非setAttribute方法

   * 设定属性值的提取方式
   * hasBooleanValue: 属性值设为否值时不添加到dom元素上
   * hasNumericValue: 属性值须设置为数值型或可转化成数值型的字符串,否则不添加到dom元素上
   * hasPositiveNumericValue: 属性值须设置为正数,否则不添加到dom元素上
   * hasOverloadedBooleanValue: 属性值为false时不添加到dom元素上
   */
  properties: {},

  // 存储小写形式的节点属性到react节点属性的映射,如{class:"className"}等;调试用
  getPossibleStandardName: process.env.NODE_ENV !== 'production' ? { autofocus: 'autoFocus' } : null,

  // 存储各节点属性插件的isCustomAttribute方法,如HTMLDOMPropertyConfig模块的isCustomAttribute方法
  _isCustomAttributeFunctions: [],

  // 是否允许设置dom节点的自定义属性attributeName,如HTMLDOMPropertyConfig模块设定以data-或aria-起始的属性名
  isCustomAttribute: function (attributeName) {
    for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
      var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
      if (isCustomAttributeFn(attributeName)) {
        return true;
      }
    }
    return false;
  },

  // 通过ReactDefaultInjection模块加载节点属性插件,如ARIADOMPropertyConfig、HTMLDOMPropertyConfig、SVGDOMPropertyConfig
  // 最终为当前模块的DOMProperty.properties、DOMProperty._isCustomAttributeFunctions注入内容
  injection: DOMPropertyInjection
};

module.exports = DOMProperty;

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值