Css in Js 一次實踐
最近需要做一個表格元件,元件需求:
- 指定行、列
- 可以跨行、跨列
- 行和行之間有分割線
最終採用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
原始碼解答上述問題。
最後,祝生活愉快。