Css in Js 一次实践

6次阅读

共计 2782 个字符,预计需要花费 7 分钟才能阅读完成。

最近需要做一个表格组件,组件需求:

指定行、列
可以跨行、跨列
行和行之间有分割线

最终采用 grid 实现需求。实现的时候遇到一个问题,如果 css 和 js 分开写,css 只能是定值,没有灵活性。所以考虑采用 css in js 的形式。关于 css in js 相关的概念介绍可以参考阮一峰老师的文章:css in js 介绍。
在 github 上找了一下关于这方面的组件,发现 styled components 非常不错,简单易上手,
npm 下载:`npm i styled-components -S`
注意:
React < 16 需要下载 3.x.x 版本的

根据文档先写一个简单的 demo。

可以看到,它的实现方式并不是传统的以对象的形式写样式,而是将需要添加样式的元素加到 styled 对象上,然后跟一个 (“) 反引号标签,在里面以正常的 css 格式写样式。然后返回一个组件,把组件替换原来的 div 即可。
实现效果:
html 代码:
css 代码:
刚才我们添加样式的元素是 html 元素,那么给组件添加样式可以么?实践一下:
const H1 = ({className}) => <h3 className={className}> 我是 App</h3>;
const HH = styled.H1`
font-size: 30px;
color: red;
`;
运行,报错:

咋回事?原来 styled 不支持以 . 符号的形式为组件添加样式,需要以参数形式传递,修改上面代码
const HH = styled(H1)`
font-size: 30px;
color: red;
`;
将 H1 组件以参数形式传递给 styled, 就可以了。

想给元素添加伪元素样式,子元素样式可以么?没问题,styled components 支持样式嵌套,按照类似 Less 或 Scss 的书写方式就可以了。
const Container = styled.div`
width: 300px;
max-width: 500px;
min-width: 200px;
transition: all 1s ease-in-out;
background-color: rgba(240, 240, 240, 0.9);
::after {
content: ‘after’;
display: table;
color: blue;
}
span {
color: green;
}
`;
以上我们写的组件都是在 Class 外面,那我们要根据 props 设定样式怎么办?styled components 同样支持在 Class 内生成组件,并接受 props 传递过来的值,这个 props 并不是我们的 Class 接收的 props,它是添加样式的元素上的 Props,意思就是
class Demo {

render(){
return <Styled name=”guoshi”></Styled>
}
}

Demo.defaultProps = {
age: 18
}

const Styled = styled.p`
color: ${props=>{console.log(props)}} // {name: “guoshi”,theme:{…}}
`

如果想使用 Class 的 props 怎么办?看代码:
generateStyle = () => {
const {row, col, justify, data, prefixCls, showborder = true, rowgap = 0, colgap = 0} = this.props;
const child = [];
data.map((item,index)=> (item.colSpan || item.rowSpan) ? child.push({index:index+1,colSpan:item.colSpan, rowSpan:item.rowSpan}):null);
const bordernone = [];
for(let i = 0; i < row; i++) {
bordernone.push(1 + i*col);
}
const UlContainer = styled.ul.attrs({className: prefixCls})`
display: grid;
grid-template-columns: ${()=> {
let arr = [];
arr.length = col;
return arr.fill(‘1fr’).join(‘ ‘);
}};
grid-template-rows: ${()=> {
let arr = [];
arr.length = row;
return arr.fill(‘1fr’).join(‘ ‘);
}};
grid-gap: ${rowgap} ${colgap} ;
justify-items: ${()=> justify || “center”};

::before {
display: none;
}

li {
width: 100% !important;
}

${
child.map(({index, colSpan, rowSpan}) =>`
li:nth-child(${index}) {
grid-column-start: ${index%col === 0 ? index : index%col};
grid-column-end: ${colSpan ? (colSpan+(index%col === 0 ? index : index%col)) : ((index%col === 0 ? index : index%col)+1)}
grid-row-start: ${Math.ceil(index/col)};
grid-row-end: ${rowSpan ? rowSpan+Math.ceil(index/col) : Math.ceil(index/col)+1};
align-items: start;
}
`).join(‘ ‘)
}

li + li {
border-left: 1px dashed rgba(0,0,0,0.3);
}

${
bordernone.map(bordernoneindex=>`
li:nth-child(${bordernoneindex}) {
border-left: none;
}
`).join(‘ ‘)
}

`;

return UlContainer;
}
提前把最后代码放出来了,styled.ul.attrs({})就是为元素添加额外的属性,比如 className、placeholder 等,从代码中可以看到,无论是 Class 的 props 还是元素自身传进来的 props,styled 都可以接收, 你可以自定义任何你想实现的规则, 更方便我们配置的灵活性。
其实到这里,使用上没有任何问题了,关于 keyframes 等规则官网上都有 demo,也非常容易实现。想尝试的小伙伴现在就可以码一遍。不过本章遗留了很多问题:

styled.div & styled(div) 有什么区别
模版字符串中的样式是怎么解析的?为什么可以嵌套?
为什么会返回一个组件?

下一章,我会根据 styled componnets 源码解答上述问题。
最后,祝生活愉快。

正文完
 0