CSSPropertyOperations模块用于拼接样式字符串,或者对节点添加样式。
dangerousStyleValue模块对数值或数值型字符串拼接"px"单位,其他转化为字符串输出。
CSSProperty模块存储无单位样式名的集合、background等复合样式名的集合。
CSSPropertyOperations.js
'use strict'; // 无单位样式及复合样式的集合 var CSSProperty = require('./CSSProperty'); var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); var ReactInstrumentation = require('./ReactInstrumentation'); // 字符串拼接的样式名转化为驼峰式输出 var camelizeStyleName = require('fbjs/lib/camelizeStyleName'); // 对数值或数值型字符串添加”px“单位处理,其他转化为字符串 var dangerousStyleValue = require('./dangerousStyleValue'); // 将"backgroundColor"转化为"background-color","MozTransition"转化为"-moz-transition" // "msTransition"转化为"-ms-transition" // 驼峰式样式名转化为连字符输出 var hyphenateStyleName = require('fbjs/lib/hyphenateStyleName'); // 键值对缓存,回调函数以属性名为参数,返回值作为属性值;有属性值直接取值,不执行回调 var memoizeStringOnly = require('fbjs/lib/memoizeStringOnly'); var warning = require('fbjs/lib/warning'); // 驼峰式样式名转化为连字符输出,并键值对缓存驼峰式样式名、连字符拼接的样式名 var processStyleName = memoizeStringOnly(function (styleName) { return hyphenateStyleName(styleName); }); // ie8下,是否不能对background等复合样式属性设为"",需要逐个设置backgroundColor样式为"" var hasShorthandPropertyBug = false; // 特定浏览器下浮动样式属性名 var styleFloatAccessor = 'cssFloat'; if (ExecutionEnvironment.canUseDOM) { var tempStyle = document.createElement('div').style; try { tempStyle.font = ''; } catch (e) { hasShorthandPropertyBug = true; } if (document.documentElement.style.cssFloat === undefined) { styleFloatAccessor = 'styleFloat'; } } if (process.env.NODE_ENV !== 'production') { // 'msTransform' is correct, but the other prefixes should be capitalized var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; var badStyleValueWithSemicolonPattern = /;\s*$/; var warnedStyleNames = {}; var warnedStyleValues = {}; var warnedForNaNValue = false; // 样式属性名含有"-"连字符号时作警告处理 var warnHyphenatedStyleName = function (name, owner) { if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { return; } warnedStyleNames[name] = true; process.env.NODE_ENV !== 'production' ? warning(false, 'Unsupported style property %s. Did you mean %s?%s', name, camelizeStyleName(name), checkRenderMessage(owner)) : void 0; }; // 特定浏览器样式属性名校验,webkit|moz|o首字母须为大写形式 var warnBadVendoredStyleName = function (name, owner) { if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { return; } warnedStyleNames[name] = true; process.env.NODE_ENV !== 'production' ? warning(false, 'Unsupported vendor-prefixed style property %s. Did you mean %s?%s', name, name.charAt(0).toUpperCase() + name.slice(1), checkRenderMessage(owner)) : void 0; }; // 样式值不能含有分号校验 var warnStyleValueWithSemicolon = function (name, value, owner) { if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { return; } warnedStyleValues[value] = true; process.env.NODE_ENV !== 'production' ? warning(false, 'Style property values shouldn\'t contain a semicolon.%s ' + 'Try "%s: %s" instead.', checkRenderMessage(owner), name, value.replace(badStyleValueWithSemicolonPattern, '')) : void 0; }; // 样式值为NaN时警告处理 var warnStyleValueIsNaN = function (name, value, owner) { if (warnedForNaNValue) { return; } warnedForNaNValue = true; process.env.NODE_ENV !== 'production' ? warning(false, '`NaN` is an invalid value for the `%s` css style property.%s', name, checkRenderMessage(owner)) : void 0; }; var checkRenderMessage = function (owner) { if (owner) { var name = owner.getName(); if (name) { return ' Check the render method of `' + name + '`.'; } } return ''; }; // 样式校验,样式名不能含有"-"连字符、webkit|moz|o首字母须为大写形式;样式值不能含有分号,及不能是NaN var warnValidStyle = function (name, value, component) { var owner; if (component) { owner = component._currentElement._owner; } // 样式属性含有"-"连字符号时作警告处理 if (name.indexOf('-') > -1) { warnHyphenatedStyleName(name, owner); // 特定浏览器样式属性名校验,webkit|moz|o首字母须为大写形式 } else if (badVendoredStyleNamePattern.test(name)) { warnBadVendoredStyleName(name, owner); // 样式值不能含有分号校验 } else if (badStyleValueWithSemicolonPattern.test(value)) { warnStyleValueWithSemicolon(name, value, owner); } // 样式值为NaN时警告处理 if (typeof value === 'number' && isNaN(value)) { warnStyleValueIsNaN(name, value, owner); } }; } // 以字符串拼接节点的样式,或以node.style[styleName]=value设置节点的样式 var CSSPropertyOperations = { // 将样式拼接为字符串输出 createMarkupForStyles: function (styles, component) { var serialized = ''; for (var styleName in styles) { if (!styles.hasOwnProperty(styleName)) { continue; } var styleValue = styles[styleName]; if (process.env.NODE_ENV !== 'production') { warnValidStyle(styleName, styleValue, component); } if (styleValue != null) { // processStyleName函数将驼峰式样式名转化为连字符输出 serialized += processStyleName(styleName) + ':'; // dangerousStyleValue函数对数值或数值型字符串添加”px“单位处理,其他转化为字符串 serialized += dangerousStyleValue(styleName, styleValue, component) + ';'; } } return serialized || null; }, // 通过node.style[styleName]=value以对象形式设置节点的样式 setValueForStyles: function (node, styles, component) { if (process.env.NODE_ENV !== 'production') { ReactInstrumentation.debugTool.onHostOperation({ instanceID: component._debugID, type: 'update styles', payload: styles }); } var style = node.style; for (var styleName in styles) { if (!styles.hasOwnProperty(styleName)) { continue; } if (process.env.NODE_ENV !== 'production') { // warnValidStyle样式校验,样式名不能含有"-"连字符、webkit|moz|o首字母须为大写形式;样式值不能含有分号,及不能是NaN warnValidStyle(styleName, styles[styleName], component); } // dangerousStyleValue函数对数值或数值型字符串添加”px“单位处理,其他转化为字符串 var styleValue = dangerousStyleValue(styleName, styles[styleName], component); // 置换为特定浏览器下浮动样式属性名,'cssFloat'或'styleFloat' if (styleName === 'float' || styleName === 'cssFloat') { styleName = styleFloatAccessor; } if (styleValue) { style[styleName] = styleValue; } else { // ie8下,对background等复合样式属性,逐个设置backgroundColor样式为"" var expansion = hasShorthandPropertyBug && CSSProperty.shorthandPropertyExpansions[styleName]; if (expansion) { for (var individualStyleName in expansion) { style[individualStyleName] = ''; } } else { style[styleName] = ''; } } } } }; module.exports = CSSPropertyOperations;
dangerousStyleValue.js
'use strict'; var CSSProperty = require('./CSSProperty'); var warning = require('fbjs/lib/warning'); // 无单位样式 var isUnitlessNumber = CSSProperty.isUnitlessNumber; var styleWarnings = {}; // 数值或数值型字符串样式值添加"px"作单位,其他转化为字符串输出 function dangerousStyleValue(name, value, component) { var isEmpty = value == null || typeof value === 'boolean' || value === ''; if (isEmpty) { return ''; } // 无单位样式直接转化为字符串 var isNonNumeric = isNaN(value);// 数值或数值型字符串返回false if (isNonNumeric || value === 0 || isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) { return '' + value; } // 数值型且非0字符串警告未来将作为无单位样式值处理,不会自动拼接上"px"单位 if (typeof value === 'string') { if (process.env.NODE_ENV !== 'production') { if (component && value !== '0') { var owner = component._currentElement._owner; var ownerName = owner ? owner.getName() : null; if (ownerName && !styleWarnings[ownerName]) { styleWarnings[ownerName] = {}; } var warned = false; if (ownerName) { var warnings = styleWarnings[ownerName]; warned = warnings[name]; if (!warned) { warnings[name] = true; } } if (!warned) { process.env.NODE_ENV !== 'production' ? warning(false, 'a `%s` tag (owner: `%s`) was passed a numeric string value ' + 'for CSS property `%s` (value: `%s`) which will be treated ' + 'as a unitless number in a future version of React.', component._currentElement.type, ownerName || 'unknown', name, value) : void 0; } } } value = value.trim(); } // 数值或数值型字符串样式值添加"px"作单位 return value + 'px'; } module.exports = dangerousStyleValue;
CSSProperty.js
'use strict'; // 无单位样式,有单位样式会对数值型字符串拼接px单位 var isUnitlessNumber = { animationIterationCount: true, borderImageOutset: true, borderImageSlice: true, borderImageWidth: true, boxFlex: true, boxFlexGroup: true, boxOrdinalGroup: true, columnCount: true, flex: true, flexGrow: true, flexPositive: true, flexShrink: true, flexNegative: true, flexOrder: true, gridRow: true, gridColumn: true, fontWeight: true, lineClamp: true, lineHeight: true, opacity: true, order: true, orphans: true, tabSize: true, widows: true, zIndex: true, zoom: true, // SVG-related properties fillOpacity: true, floodOpacity: true, stopOpacity: true, strokeDasharray: true, strokeDashoffset: true, strokeMiterlimit: true, strokeOpacity: true, strokeWidth: true }; function prefixKey(prefix, key) { return prefix + key.charAt(0).toUpperCase() + key.substring(1); } var prefixes = ['Webkit', 'ms', 'Moz', 'O']; // 特定浏览器下的无单位样式 Object.keys(isUnitlessNumber).forEach(function (prop) { prefixes.forEach(function (prefix) { isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; }); }); // background等复合样式,ie8不能对style.background赋值为"",而需要对style.background.backgroundColor等赋值为"" var shorthandPropertyExpansions = { background: { backgroundAttachment: true, backgroundColor: true, backgroundImage: true, backgroundPositionX: true, backgroundPositionY: true, backgroundRepeat: true }, backgroundPosition: { backgroundPositionX: true, backgroundPositionY: true }, border: { borderWidth: true, borderStyle: true, borderColor: true }, borderBottom: { borderBottomWidth: true, borderBottomStyle: true, borderBottomColor: true }, borderLeft: { borderLeftWidth: true, borderLeftStyle: true, borderLeftColor: true }, borderRight: { borderRightWidth: true, borderRightStyle: true, borderRightColor: true }, borderTop: { borderTopWidth: true, borderTopStyle: true, borderTopColor: true }, font: { fontStyle: true, fontVariant: true, fontWeight: true, fontSize: true, lineHeight: true, fontFamily: true }, outline: { outlineWidth: true, outlineStyle: true, outlineColor: true } }; var CSSProperty = { // 无单位样式名的集合,有单位样式会对数值型字符串拼接px单位 isUnitlessNumber: isUnitlessNumber, // background等复合样式,ie8不能对style.background赋值为"",而需要对style.background.backgroundColor等赋值为"" shorthandPropertyExpansions: shorthandPropertyExpansions }; module.exports = CSSProperty;