最近在尝试使用styled-components来做React下的样式开发,这样可以利用js语言的灵活来增强css的能力。
在多屏适配这块,一直是在使用淘宝的lib-flexible。
在用styled-components处理px到rem的转换时,有点问题了。styled-components自己本着基础库的原则,是没有附加这些复杂的配置,所以一开始想的是自己写一个函数来做单位换算:
function r(pxValue) {
const ratio = 20; // 根据项目配置比例的方式自行设定
pxValue = parseInt(pxValue);
return pxValue / ratio + 'rem';
}
然后在写样式的时候这样写
// 保留了px的单位而不是传递数字,使得代码具有可读性,方便维护
let AvatarImage = styled(Image)`
width: ${r('132px')};
height: ${r('132px')};
`;
这样满足了基本需求。
不过作为喜欢偷懒喜欢折腾的程序员,总觉得这样写很啰嗦,所以想着能不能也跟styled-components那样使用标签模版的功能
所以也就有了第二版的function r:
function r(pxValue) {
const ratio = 20; // 根据项目配置比例的方式自行设定
// 针对template literals
if (Array.isArray(pxValue)) {
pxValue = pxValue[0];
}
pxValue = parseInt(pxValue);
return pxValue / ratio + 'rem';
}
在样式书写上,就可以这样写了:
let AvatarImage = styled(Image)`
width: ${r`132px`};
height: ${r`132px`};
`;
少写了两个括号,看着也清晰多了。
不过还是不太满意,因为样式里面如果数值一多,写起来还是有点费事。
既然能够实现单个单位的换算,那用正则表达式匹配所有样式字符串里面的px值,再替换为rem值,再把计算的结果返回给styled-components不就可以了。
想法是好的,不过在读取解析已有的样式模版字符串,正则匹配,还有如何把结果传递给styled-components这些方面,坑还是很多的,折腾了一个多小时,也总算解决了。
这里面,最核心的解析已有的样式模版字符串,styled-components提供了一个helper: css,使得工作量大大减少。
function r(pxValue) {
const ratio = 20; // 根据项目配置比例的方式自行设定
// 针对template literals
if (Array.isArray(pxValue)) {
pxValue = pxValue[0];
}
pxValue = parseInt(pxValue);
return pxValue / ratio + 'rem';
}
// 把字符串样式里面的px单位换算成rem的
// 支持多行匹配
function transformPxToRem(style) {
// 避免处理了函数等情况
if (typeof style !== 'string') {
return style;
}
return style.replace(/\d+px/gm, matched => {
return r(matched);
});
}
// 实现在把样式传递给styled之前,预先用transformPxToRem处理
function t(strings, ...interpolations) {
let styles = css(strings, ...interpolations); // css是styled-components的一个helper
styles = styles.map(transformPxToRem);
// 模拟raw的调用
return [[""], styles]
};
基于以上代码,在最终书写样式的时候就可以这样:
let AvatarImage = styled(Image)(...t`
width: 132px;
height: 132px;
`);
以函数的形式调用styled-compoent,而不是标签模版的形式,同时解构t函数的返回值,这样的结果和styled-components直接计算标签模版是一样的。
不过在实现这个功能之后,在写这篇文章的时候,发现lib-flexible不再用rem作为多端适配的方案了,而是改用的vm
不过最核心的预处理部分已经实现了,后面的调整还是很容易做的。
后期的计划:
现在css helper返回的是一个数组,可以考虑join成字符串,去掉多余的空白符,然后实现css to object和object to css。然后再加上plugin机制,使得整个系统更加灵活多变。
说着说着,好像实现了一个简版的postCss。
现在styled-components是有增加babel plugin的计划来打通postCss和styled-compoent,期待。