写法demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const Button = styled.button` color: coral; padding: 0.25rem 1rem; border: solid 2px coral; border-radius: 3px; margin: 0.5rem; font-size: 1rem; `;
const Button = styled('button')([ 'color: coral;' + 'padding: 0.25rem 1rem;' + 'border: solid 2px coral;' + 'border-radius: 3px;' + 'margin: 0.5rem;' + 'font-size: 1rem;' ]);
|
原理分析
生成带有样式的标签
难点在于理解这种看起来很高级的写法,本质上就是函数调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const myStyled = (TargetComponent) => ([style]) => class extends React.Component { componentDidMount() { this.element.setAttribute('style', style); } render() { return ( <TargetComponent {...this.props} ref={element => this.element = element } /> ); } };
const Button = myStyled('button')` color: coral; padding: 0.25rem 1rem; border: solid 2px coral; border-radius: 3px; margin: 0.5rem; font-size: 1rem; `;
|
支持获取props
难点在于如何识别带有动态参数的写法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| const myStyled = (TargetComponent) => (strs, ...exprs) => class extends React.Component { interpolateStyle() { const style = exprs.reduce((result, expr, index) => { const isFunc = typeof expr === 'function'; const value = isFunc ? expr(this.props) : expr;
return result + value + strs[index + 1]; }, strs[0]);
this.element.setAttribute('style', style); }
componentDidMount() { this.interpolateStyle(); }
componentDidUpdate() { this.interpolateStyle(); }
render() { return <TargetComponent {...this.props} ref={element => this.element = element } /> } };
const primaryColor = 'coral';
const Button = myStyled('button')` background: ${({ primary }) => primary ? primaryColor : 'white'}; color: ${({ primary }) => primary ? 'white' : primaryColor}; padding: 0.25rem 1rem; border: solid 2px ${primaryColor}; border-radius: 3px; margin: 0.5rem; font-size: 1rem; `;
|
计算类名和css
前面是把style直接赋给了元素。实际上,这里是给元素挂入了一个hash后的className,classname对应的样式是style。
具体流程如下:
解析具体的 style,比如前面的 interpolateStyle
函数
利用 murmurhash 算法,将 style + 一个全局递增的id拼接传入,生成对应className
利用 stylis 提取对应的 css 。传入的参数就是 className 以及 style,会自动生成css的标准写法
将css注入到页面的 <style>
标签中
1 2 3 4 5
| function insertCss(css: string, index = 0) { const { styleSheets } = document; styleSheets[0].insertRule(css, index); }
|
讲classname给到元素上即可
参考文档