五分钟 Styled-components 高级实用技巧

写在前面的废话

回到2013年,React凭空出世。可是在那时,咱们会想,oh shit! 咱们好不容易分离了HTML/CSS/JS, 为何出现了JSX,咱们又须要把HTML和JS耦合在一块儿?React 创造了 HTML in JS. 在React中,咱们知道,一切即组件。那既然HTML能在js里写,为何咱们不把CSS也一块儿写呢?这样不才是一个真正的组件吗?javascript

Styled-components就是为React而生的,它是CSS in JS的下一代解决方案。以往咱们想要作到css scope都须要在webpack中各类配置,或者使用js的解决方案。而styled-components你只须要import styled from 'styled-components';便可。css

甚至React完美的结合,不只是从TagName上,还有Props上。使咱们的代码有更好的语义化,可维护性更强,效率更高。固然咱们无需考虑它的学习成本,只要你用过CSS或者SASS均可以马上上手,由于它自己就是一种超集的存在。html

接下来,我会逐步的介绍一些这段时间以来,我很是喜欢的独有的特性。

开胃菜

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继承样式有两种写法以下java

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 权重覆盖。不推荐react

固然,还有一种有趣的“继承” withComponent,咱们能够利用withComponent改变渲染的标签webpack

const Li = styled.li`
    color:#abcdef;
`;
const A = Li.withComponent('a'); // 将会渲染a标签

编译后他们会使用不一样的className,这对咱们想用同个样式,可是不一样标签很是有用。git

样式覆盖

这里所说的样式覆盖,主要是一些交互上的行为(hover, active)覆盖。其实组件继承也算是覆盖的一种。

以往咱们的覆盖写法以下:es6

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进行引用,从而覆盖样式,以下github

const Icon = styled.span`
    color: red;
`;

const ListItem = styled.li`

    &:hover ${Icon} {
        color: green;
    }
`;

这依旧是咱们过去的思路来覆盖样式,只是咱们把选择器直接使用styled组件引用罢了。拥有这样的接口,就更加让咱们无需去思考须要给组件取什么className或者id,从而达到覆盖样式的作法。然而还有我最喜欢的另一种写法。web

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

相关文章
相关标签/搜索