DOMPropertyOperations

DOMPropertyOperations节点属性操作,用于添加或移除节点属性。

 

'use strict';

var DOMProperty = require('./DOMProperty');
var ReactDOMComponentTree = require('./ReactDOMComponentTree');
var ReactInstrumentation = require('./ReactInstrumentation');

// 布尔、数值型转化为字符串,字符串经html转码,处理["'&<>];外加引号包裹
var quoteAttributeValueForBrowser = require('./quoteAttributeValueForBrowser');

var warning = require('fbjs/lib/warning');

// 用于校验属性名,英文字母a-zA-Z、":"、"-"、数字、部分Unicode字符形式
var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + DOMProperty.ATTRIBUTE_NAME_START_CHAR + '][' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$');

var illegalAttributeNameCache = {};// 缓存校验失败的属性名
var validatedAttributeNameCache = {};// 缓存校验成功的属性名

// 校验属性名,英文字母a-zA-Z、":"、"-"、数字、部分Unicode字符形式
function isAttributeNameSafe(attributeName) {
  if (validatedAttributeNameCache.hasOwnProperty(attributeName)) {
    return true;
  }
  if (illegalAttributeNameCache.hasOwnProperty(attributeName)) {
    return false;
  }
  if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) {
    validatedAttributeNameCache[attributeName] = true;
    return true;
  }
  illegalAttributeNameCache[attributeName] = true;
  process.env.NODE_ENV !== 'production' ? 
    warning(false, 'Invalid attribute name: `%s`', attributeName) : void 0;
  return false;
}

// 属性值约定的布尔型真值校验(否值忽略)、数值型校验、正数校验
function shouldIgnoreValue(propertyInfo, value) {
  return value == null || propertyInfo.hasBooleanValue && !value || 
    propertyInfo.hasNumericValue && isNaN(value) || 
    propertyInfo.hasPositiveNumericValue && value < 1 || 
    propertyInfo.hasOverloadedBooleanValue && value === false;
}

var DOMPropertyOperations = {

  // 以字符串形式设置节点的'data-reactid'属性及值;拼接字符串的方式创建节点时使用
  createMarkupForID: function (id) {
    return DOMProperty.ID_ATTRIBUTE_NAME + '=' + quoteAttributeValueForBrowser(id);
  },

  // 设置节点的'data-reactid'的属性;document.createElement方式创建节点时使用
  setAttributeForID: function (node, id) {
    node.setAttribute(DOMProperty.ID_ATTRIBUTE_NAME, id);
  },

  // 以字符串形式设置节点的'data-reactroot'属性及值;拼接字符串的方式创建节点时使用
  createMarkupForRoot: function () {
    return DOMProperty.ROOT_ATTRIBUTE_NAME + '=""';
  },

  // 设置节点的'data-reactroot'属性;document.createElement方式创建节点时使用
  setAttributeForRoot: function (node) {
    node.setAttribute(DOMProperty.ROOT_ATTRIBUTE_NAME, '');
  },

  // 提取特定属性及其值,拼接为字符串形式
  // DOMProperty.properties、DOMProperty.isCustomAttribute约定可设置的节点属性
  // DOMProperty.properties用于提取或忽略属性值,如properties.hasBooleanValue会忽略属性值为否值的配置项
  // DOMProperty.isCustomAttribute校验可自定义添加的属性,如data-或aria-起始的属性
  createMarkupForProperty: function (name, value) {
    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null;
    if (propertyInfo) {

      // 以propertyInfo约定的属性值类型忽略某些属性值value,如properties.hasBooleanValue设置会忽略属性值为否值的value
      if (shouldIgnoreValue(propertyInfo, value)) {
        return '';
      }
      var attributeName = propertyInfo.attributeName;
      if (propertyInfo.hasBooleanValue || propertyInfo.hasOverloadedBooleanValue && value === true) {
        return attributeName + '=""';
      }
      return attributeName + '=' + quoteAttributeValueForBrowser(value);
    } else if (DOMProperty.isCustomAttribute(name)) {
      if (value == null) {
        return '';
      }
      return name + '=' + quoteAttributeValueForBrowser(value);
    }
    return null;
  },

  // 字符串形式设置自定义属性
  createMarkupForCustomAttribute: function (name, value) {
    if (!isAttributeNameSafe(name) || value == null) {
      return '';
    }
    return name + '=' + quoteAttributeValueForBrowser(value);
  },

  // 设置节点属性,最常使用setAttribute或setAttributeNS方法
  // 特别当propertyInfo.mutationMethod存在时,使用该方法设置节点属性
  // 或propertyInfo.mustUseProperty为真值时,使用node[propertyInfo.propertyName]=value设置节点属性
  // 或通过DOMProperty.isCustomAttribute校验的属性,根据value值移除或添加节点属性
  setValueForProperty: function (node, name, value) {
    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null;
    if (propertyInfo) {

      // 以节点属性插件的DOMMutationMethods配置方法添加节点属性
      var mutationMethod = propertyInfo.mutationMethod;
      if (mutationMethod) {
        mutationMethod(node, value);

      // 以propertyInfo约定的属性值类型忽略某些属性值value,如properties.hasBooleanValue设置会忽略属性值为否值的value
      } else if (shouldIgnoreValue(propertyInfo, value)) {
        this.deleteValueForProperty(node, name);
        return;

      // propertyInfo.mustUseProperty为真值时,不用setAttribute方法设置节点属性
      // 处理ie8、9setAttribute方法将属性值转换成字符串`[object]`的兼容性问题
      } else if (propertyInfo.mustUseProperty) {
        node[propertyInfo.propertyName] = value;
      } else {
        var attributeName = propertyInfo.attributeName;
        var namespace = propertyInfo.attributeNamespace;

        // node.setAttributeNS(namespace,attr,value)添加特定命名空间的属性
        if (namespace) {
          node.setAttributeNS(namespace, attributeName, '' + value);
        // 布尔型往节点注入属性名即可
        } else if (propertyInfo.hasBooleanValue || propertyInfo.hasOverloadedBooleanValue && value === true) {
          node.setAttribute(attributeName, '');
        } else {
          node.setAttribute(attributeName, '' + value);
        }
      }
    // 对通过DOMProperty.isCustomAttribute校验的属性,根据value值移除或添加属性
    } else if (DOMProperty.isCustomAttribute(name)) {
      DOMPropertyOperations.setValueForAttribute(node, name, value);
      return;
    }

    if (process.env.NODE_ENV !== 'production') {
      var payload = {};
      payload[name] = value;
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
        type: 'update attribute',
        payload: payload
      });
    }
  },

  // 根据value值添加或移除属性
  setValueForAttribute: function (node, name, value) {
    if (!isAttributeNameSafe(name)) {
      return;
    }
    if (value == null) {
      node.removeAttribute(name);
    } else {
      node.setAttribute(name, '' + value);
    }

    if (process.env.NODE_ENV !== 'production') {
      var payload = {};
      payload[name] = value;
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
        type: 'update attribute',
        payload: payload
      });
    }
  },

  // 移除节点node的属性name
  deleteValueForAttribute: function (node, name) {
    node.removeAttribute(name);
    if (process.env.NODE_ENV !== 'production') {
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
        type: 'remove attribute',
        payload: name
      });
    }
  },

  // 移除节点属性,最常使用removeAttribute方法
  // 特别当propertyInfo.mutationMethod存在时,使用该方法移除节点属性
  // 或propertyInfo.mustUseProperty为真值时,使用node[propertyInfo.propertyName]移除节点属性
  deleteValueForProperty: function (node, name) {
    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null;
    if (propertyInfo) {
      var mutationMethod = propertyInfo.mutationMethod;
      if (mutationMethod) {
        mutationMethod(node, undefined);
      } else if (propertyInfo.mustUseProperty) {
        var propName = propertyInfo.propertyName;
        if (propertyInfo.hasBooleanValue) {
          node[propName] = false;
        } else {
          node[propName] = '';
        }
      } else {
        node.removeAttribute(propertyInfo.attributeName);
      }
    } else if (DOMProperty.isCustomAttribute(name)) {
      node.removeAttribute(name);
    }

    if (process.env.NODE_ENV !== 'production') {
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
        type: 'remove attribute',
        payload: name
      });
    }
  }

};

module.exports = DOMPropertyOperations;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值