styled-components
style-components是针对React写的一套css in js(有利于组件的隔离)框架,简单来讲就是在js中写css。 相对于与预处理器 (sass、less)的好处是,css in js使用的是js语法,不用重新再学习新技术,也不会多一道编译步骤。无疑会加快网页速度。
一、使用方法
1.安装
从 npm 安装 styled-components :
npm install --save styled-components
添加 styled-components 之后就可以访问全局的 window.styled 变量.
import styled from "styled-components"
const Button = styled.button`
display: inline-block;
margin: 1em;
padding:5px;
font-size:16px;
text-decoration:none;
color:#fff;
border:none;
//基于props属性的适配
background-color:${props =>props.type==='primary'?"blue":"red" };
`;
export default Button
2.基于props属性的适配与传递
- 基于属性的适配 我们可以将 props 以插值的方式传递给styled component,以调整组件样式.
const Button = styled.button`
/* Adapt the colors based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
render(
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
</div>
);
- 属性传递
如果添加样式的目标是 DOM 元素 (如styled.div), styled-components 会传递已知的 HTML 属性给 DOM. 如果是一个自定义的 React 组件 (如styled(MyComponent)), styled-components 会传递全部 props.
以下示例展示如何传递 Input 组件的 props 到已装载的 DOM 节点, as with React elements.
// 创建一个给<input>标签添加若干样式的 Input 组件
const Input = styled.input`
padding: 0.5em;
margin: 0.5em;
color: ${props => props.inputColor || "palevioletred"};
background: papayawhip;
border: none;
border-radius: 3px;
`;
// 渲染两个样式化的 text input,一个标准颜色,一个自定义颜色
render(
<div>
<Input defaultValue="@probablyup" type="text" />
<Input defaultValue="@geelen" type="text" inputColor="rebeccapurple" />
</div>
);
注意, inputColor prop并没有传递给 DOM, 但是type和defaultValue 都传递了. styled-components足够智能,会自动过滤掉所有非标准 attribute.
3.styled-component样式
- 样式继承 创建一个继承其它组件样式的新组件,最简单的方式就是用构造函数styled()包裹被继承的组件。
const Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// 一个继承 Button 的新组件, 重载了一部分样式
const TomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`;
render(
<div>
<Button>Normal Button</Button>
<TomatoButton>Tomato Button</TomatoButton>
</div>
);
- 通过as作为prop,在不改变样式的前提下改变元素(像导航栏同时存在按钮与链接,但它们样式相同)
const Button = styled.button`
display: inline-block;
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
const TomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`;
render(
<div>
<Button>Normal Button</Button>
<Button as="a" href="/">Link with Button styles</Button>
<TomatoButton as="a" href="/">Link with Tomato Button styles</TomatoButton>
</div>
);
这也完美适用于自定义组件:
const Button = styled.button`
display: inline-block;
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
const ReversedButton = props => <button {...props} children={props.children.split('').reverse()} />
render(
<div>
<Button>Normal Button</Button>
<Button as={ReversedButton}>Custom Button with Normal Button styles</Button>
</div>
);
- 给任何组件添加样式 styled方法适用于任何最终向 DOM 元素传递 className 属性的组件,当然也包括第三方组件.
// 下面是给 react-router-dom Link 组件添加样式的示例
const Link = ({ className, children }) => (
<a className={className}>
{children}
</a>
);
const StyledLink = styled(Link)`
color: palevioletred;
font-weight: bold;
`;
render(
<div>
<Link>Unstyled, boring Link</Link>
<br />
<StyledLink>Styled, exciting Link</StyledLink>
</div>
);
注意:在 render 方法之外定义 Styled Components
在 render 方法之外(组件之外)定义 styled component 很重要, 不然 styled component 会在每个渲染过程中重新创建. 这将阻止缓存生效并且大大降低了渲染速度,所以尽量避免这种情况.
推荐通过以下方式创建 styled components :
const StyledWrapper = styled.div`
/* ... */
`
const Wrapper = ({ message }) => {
return <StyledWrapper>{message}</StyledWrapper>
}
4.伪元素、伪类选择器和嵌套
伪元素和伪类无需进一步细化,而是自动附加到了组件:
const Thing = styled.button`
color: blue;
::before { content: '????';
}
:hover {
color: red;
} `
render(
<Thing>Hello world!</Thing>
)
对于更复杂的选择器,可以使用与号(&)来指向主组件(Thing).以下是一些示例:
const Thing = styled.div.attrs({ tabIndex: 0 })`
color: blue;
&:hover {
color: red; // <Thing> when hovered
}
& ~ & {
background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it
}
& + & {
background: lime; // <Thing> next to <Thing>
}
&.something {
background: orange; // <Thing> tagged with an additional CSS class ".something"
}
.something-else & {
border: 1px solid; // <Thing> inside another element labeled ".something-else"
}
`
render(
<React.Fragment>
<Thing>Hello world!</Thing>
<Thing>How ya doing?</Thing>
<Thing className="something">The sun is shining...</Thing>
<div>Pretty nice day today.</div>
<Thing>Don't you think?</Thing>
<div className="something-else">
<Thing>Splendid.</Thing>
</div>
</React.Fragment>
)
如果只写选择器而不带&,则指向组件的子节点.
const Thing = styled.div`
color: blue;
.something {
border: 1px solid; // an element labeled ".something" inside <Thing>
display: block;
}
`
render(
<Thing>
<label htmlFor="foo-button" className="something">Mystery button</label>
<button id="foo-button">What do I do?</button>
</Thing>
)
最后,&可以用于增加组件的差异性;在处理混用 styled-components 和纯 CSS 导致的样式冲突时这将会非常有用:
const Thing = styled.div`
&& {
color: blue;
}
`
const GlobalStyle = createGlobalStyle`
div${Thing} {
color: red;
}
`
render(
<React.Fragment>
<GlobalStyle />
<Thing>
I'm blue, da ba dee da ba daa
</Thing>
</React.Fragment>
)
5.加额外的属性 .attrs
为了避免仅为传递一些props来渲染组件或元素而使用不必要的wrapper, 可以使用 .attrs constructor. 通过它可以添加额外的 props 或 attributes 到组件.
const Input = styled.input.attrs({
// static props
type: "password",
// dynamic props
margin: props => props.size || "1em",
padding: props => props.size || "1em"
})`
color: palevioletred;
font-size: 1em;
border: 2px solid palevioletred;
border-radius: 3px;
/* dynamically computed props */
margin: ${props => props.margin};
padding: ${props => props.padding};
`;
render(
<div>
<Input placeholder="A small text input" size="1em" />
<br />
<Input placeholder="A bigger text input" size="2em" />
</div>
);
6.使用动画
const rotate = keyframes` // 使用keyframes关键字
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const Rotate = styled.div`
animation: ${rotate} 2s linear infinite;
`;
render(
<Rotate>JSS</Rotate>
);
二、styled-component的优缺点
优点
1.css模块化: 尽量降低模块之间的耦合度,利于项目的进一步维护,同时因为每个样式都有其关联的组件. 如果检测到某个组件未使用并且被删除,则其所有的样式也都被删除。比起用原生的CSS,这是它首当其冲的优势。
2.支持预处理器嵌套语法。
3.解决了css类名冲突问题: styled-components 为样式生成唯一的 class name. 开发者不必再担心 class name 重复,覆盖和拼写错误的问题。
4.自动提供前缀: 按照当前标准写 CSS,其余的交给 styled-components handle 处理。
5.让CSS代码也可以处理逻辑:不仅仅是因为里面的模板字符串可以写JS表达式,更重要的是能够拿到组件的上下文信息(state、props);这样我们就可以通过一些动态的props参数,很轻松的实现主题换肤类似的功能。
6.styled-components还能很好的解决服务器渲染的样式问题
缺点
最大的缺点就是模板字符串没有css语法,无法使用代码提示。 可以在vscode安装vscode-styled-components插件,就会有提示功能。
还有一个问题,生成的页面在浏览器里面,如果想通过css的类名查找相应的组件,可以借助Babel插件进行相应的配置,方便我们在开发时调试。