共计 3040 个字符,预计需要花费 8 分钟才能阅读完成。
写在前面的废话
回到 2013 年,React 凭空出世。但是在那时,我们会想,oh shit! 我们好不容易分离了 HTML/CSS/JS, 为什么出现了 JSX,我们又需要把 HTML 和 JS 耦合在一起?React 创造了 HTML in JS. 在 React 中,我们知道,一切即组件。那既然 HTML 能在 js 里写,为什么我们不把 CSS 也一起写呢?这样不才是一个真正的组件吗?
Styled-components 就是为 React 而生的,它是 CSS in JS 的下一代解决方案。以往我们想要做到 css scope 都需要在 webpack 中各种配置,或者使用 js 的解决方案。而 styled-components 你只需要 import styled from ‘styled-components’; 即可。
甚至 React 完美的结合,不仅是从 TagName 上,还有 Props 上。使我们的代码有更好的语义化,可维护性更强,效率更高。当然我们无需考虑它的学习成本,只要你用过 CSS 或者 SASS 都可以立刻上手,因为它本身就是一种超集的存在。
接下来,我会逐步的介绍一些这段时间以来,我非常喜欢的独有的特性。
开胃菜
const Button = styled.button`
background: #abcdef;
border-radius: 3px;
border: none;
color: white;
`;
console.log(Button); //styled component
console.log(new Button()); // react component
export default CustomButton extends React.component {
render() {
return <Button {…props} />
}
}
styled-components 用了 tagged template 语法,直接为我们编写样式创建组件。
继承
styled-components 继承样式有两种写法如下
const Button = styled.button`
background: #abcdef;
border-radius: 3px;
border: none;
color: white;
`;
const OtherButton1 = styled(button)“;
const OtherButton2 = button.extend“; // 老的写法,不推荐,未来会被废弃
写法一的继承,仅仅只会创建不一样的 css rule,而第二种写法会复制一遍 base component 的 css rule,然后在添加不一样的进行 css 权重覆盖。不推荐
当然,还有一种有趣的“继承”withComponent,我们可以利用 withComponent 改变渲染的标签
const Li = styled.li`
color:#abcdef;
`;
const A = Li.withComponent(‘a’); // 将会渲染 a 标签
编译后他们会使用不同的 className,这对我们想用同个样式,但是不同标签非常有用。
样式覆盖
这里所说的样式覆盖,主要是一些交互上的行为 (hover, active) 覆盖。其实组件继承也算是覆盖的一种。
以往我们的覆盖写法如下:
const ListItem = styled.li`
padding: 0;
height: 48px;
&.left-item-focus {
.left-link {
background: ${props => props.color};
}
}
&:hover {
.left-icon {
color: #9e9e9e; // 500
}
}
`;
而在 styled 中,我们可以使用 styled-components 组件方式对我们的 DOM 进行引用,从而覆盖样式,如下
const Icon = styled.span`
color: red;
`;
const ListItem = styled.li`
&:hover ${Icon} {
color: green;
}
`;
这依旧是我们过去的思路来覆盖样式,只是我们把选择器直接使用 styled 组件引用罢了。拥有这样的接口,就更加让我们无需去思考需要给组件取什么 className 或者 id,从而达到覆盖样式的做法。然而还有我最喜欢的另外一种写法。
TIPS:组件的引用必须是 styled-components 包装后的组件,直接是 react 的会报错
const ListItem = styled.li“;
const Icon = styled.span`
color: red;
${ListItem}:hover & {// & 代表 icon 组件
color: green;
}
`;
这段代码实现的是一样的功能,只是我们思路转换了一下。可以发现这样的代码更加没有侵入性。更加符合开放封闭原则,当我们不需要这个 Icon 组件时,直接把这个 Icon 删除即可,我们不用去父组件里寻找与该组件有关的样式,不容易造成样式污染。突然觉得眼前一亮,有木有!
当然这种“子组件引用父级”的功能,还有更加广泛的引用。你可以选择该 DOM 任何 parent,再对自己进行样式的覆盖。如下:
const Icon = styled.span`
color: red;
html.ie-8 & {
// fuck ie8
color: blue;
}
body.xxx & {
color: green;
}
`;
当任何父级带有 class 都会覆盖 Icon 的样式。这种“子组件引用父级”的功能也是我最喜欢的功能没有之一。
在上面可以看见我们大量使用了 & 作为选择器,而 & 还有另外的技巧。
const Example = styled.li`
color: red;
& {
color:blue;
}
&& {
color: green;
}
`;
大家可以猜猜,这最终会渲染成什么?
<li class=’sc-gzVnrw fmpfVE’></li>
最终会编译成如下 class,但是我们的一个 & 就代表一个 class 权重也就是说我们最后会渲染原谅色,原因是 li 被作用于了.fmpfVE.fmpfVE 样式表。这个功能非常有用,比如在你使用第三方组件想要覆盖它的样式的时候,我们就可以加多个 & 来提高样式权重,从而覆盖第三方组件的样式
Theme
关于 Theme 只想说一点,那就是结合第三方组件应该如何传入 Theme 呢?我们有一个简单的技巧。比如使用了 Material-UI,如果我们需要基于它拓展我们自己的组件,并且需要样式。
const ThemeProvider: React.SFC<ThemeProviderProps> = ({themeName, children}) => {
const theme = themes[themeName];
return (
<StyledThemeProvider theme={theme}>
<MuiThemeProvider theme={theme}>
{React.Children.only(children)}
</MuiThemeProvider>
</StyledThemeProvider>
);
};
之后只需要把我们需要调用的组件使用 styled-components 提供的 withTheme 包装一下我们的组件来获取我们的 theme。
这样既可以在我们的 styled-components 里取到 theme,material 里也可以了。
以上就是我们所有的技巧了,看了这么多有意思的黑科技,难道你还不爱上 styled-components 吗?
个人网站 http://www.meckodo
Github: https://github.com/MeCKodo