01月09, 2018

react写style的一个坑

昨天交互让我改一下样式,需求大概是一个表格,然后有一个描述字段,这个是直接读取后端字段的,会有一个问题是:有些地方好几行(五六行),有些地方只有一行。她的建议是统一两行,然后用省略号。

这个css还是so easy的,出于偷懒,我就这样写了:

let style = {
    "height": 42,
    "overflow": "hidden",
    "text-overflow": "ellipsis",
    "display": "-webkit-box",
    "-webkit-box-orient": "vertical",
    "-webkit-line-clamp": "2"
}

// react代码
return (<div style={style}></div>)

看似没问题,但一查看渲染出来的结果:

alt

-webkit-line-clamp丢了,查看控制台,有一堆warning:

alt

似乎改成大小写就好了,事实上确实是OK了。

但是没完,这个激起了我的好奇心,开始翻react的源码。

其实这是react-dom的源码,相关css style的处理都在这里:

alt

找这个,其实也是靠个人经验和猜测。

然后主要操作是这个:

alt

问题是出在dangerousStyleValue方法。

先说点其他的,比如说有一个div,我们给它加点style,代码如下:

var otest = document.getElementById("test");
otest.style["text-overflow"] = "ellipsis"

alt

其实和大小写并没有太大关系,上面代码如果改成这样的:

otest.style["textOverflow"] = "ellipsis"

也能得到上面的结果,应该是webkit内核做了一层处理。

注意,前方高能,如果这样写:

otest.style["-webkit-line-clamp"] = "2px"

这个属性加不进去。但是如果将2px换成2,就OK了。所以问题就在这里。

alt

/**
 * CSS properties which accept numbers but are not in units of "px".
 */

var isUnitlessNumber = {
  animationIterationCount: true,
  borderImageOutset: true,
  borderImageSlice: true,
  borderImageWidth: true,
  boxFlex: true,
  boxFlexGroup: true,
  boxOrdinalGroup: true,
  columnCount: true,
  columns: true,
  flex: true,
  flexGrow: true,
  flexPositive: true,
  flexShrink: true,
  flexNegative: true,
  flexOrder: true,
  gridRow: true,
  gridRowEnd: true,
  gridRowSpan: true,
  gridRowStart: true,
  gridColumn: true,
  gridColumnEnd: true,
  gridColumnSpan: true,
  gridColumnStart: 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
};

/**
 * @param {string} prefix vendor-specific prefix, eg: Webkit
 * @param {string} key style name, eg: transitionDuration
 * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
 * WebkitTransitionDuration
 */
function prefixKey(prefix, key) {
  return prefix + key.charAt(0).toUpperCase() + key.substring(1);
}

/**
 * Support style names that may come passed in prefixed by adding permutations
 * of vendor prefixes.
 */
var prefixes = ['Webkit', 'ms', 'Moz', 'O'];

// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
// infinite loop, because it iterates over the newly added props too.
Object.keys(isUnitlessNumber).forEach(function (prop) {
  prefixes.forEach(function (prefix) {
    isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
  });
});

传入的name如果是-webkit-line-clamp,它找不到映射,所以返回false,就会给数值“2”加上"px"。

而如果是大写的话,WekitLineClamp就可以,看前缀的处理这一块即可知。

结论

为了偷懒,引发了一个不可预知的问题,不过也知道了style这一块的处理。

所以以后的情况,建议还是用className吧,除非是少量的style可以直接挂在style属性上。

本文链接:www.my-fe.pub/post/react-style-pit.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。