前言
styed-components 是一个基于 JavaScript 的样式库,它通过标签模板字符串的方式样式化组件,它允许我们使用 JavaScript 直接编写 CSS 样式,并且样式是组件级隔离。在网上找中文相关的资料不是很多,貌似国内用这个不多,于是我就根据我的使用经历记录一下如何使用这个库,以及和大家一起解读一下源代码是如何实现的。该知识将分为多篇文章分享记录。ps: 以下代码例子都经过我实测!
所有相关文章:
《styled-components 深入浅出 (一) : 基础使用》
《styled-components 深入浅出 (二) : 高阶组件》
基础用法
首先导入模块 styled-components, import styled from 'styled-components'
;
然后我们可以通过这个 styled
函数创建 React
组件(component) 或标签(tagname)。既然创建的是 React
组件,使用的时候当做普通的 React
组件使用就行了。
通过 styled.tagname
这种标签模板字符串的语法来创建样式化组件,其中 tagname
就是 html 的标签名。
创建自定义样式化标签
代码语言:javascript复制 const Button = styled.button`
background: blue;
border-radius: 3px;
border: none;
color: white;
`
代码语言:javascript复制<Button>Click Me</Button>
样式化组件的样式可以被继承,也可以被覆盖
代码语言:javascript复制 const Button = styled.button`
background: blue;
border-radius: 3px;
border: none;
color: white;
`
const TomatoButton = styled(Button)`
background: tomato;
`
代码语言:javascript复制<Button>Click Me</Button>
<TomatoButton>Click Me</TomatoButton>
通过传参创建动态样式
代码语言:javascript复制const padding = '10px'
export const Section = styled.section`
color: white;
/* ES 的插值语法引入变量 */
padding: ${padding};
/* 通过组件props 传参 */
background: ${props => props.$background};
`
使用的时候传入 background 参数即可
代码语言:javascript复制<Section $background={'red'}>
Section
</Section>
注意:使用 ES 的插值语法时,不支持 伪类选择器、媒体查询、嵌套等! 注意:带 $ 的参数是临时属性(Transient props)不会作用底层 React 节点或渲染到 DOM 元素,而是仅作为插值函数的参数。
styledComponent
(样式化组件)可以像普通的React组件一样使用任何属性,如果该属性是有效属性,便会作用于 HTML 节点,否则仅作为插值函数的参数。
代码语言:javascript复制export const MyInput = styled.input`
border: 1px red solid;
padding:${props => props.padding};
`
代码语言:javascript复制<MyInput type={"password"} padding={'10px'}></MyInput>
用 .attrs 给样式化组件添加属性值
styled-components 允许你给样式化组件添加属性,这些属性会作用于组件的 HTML 节点,而不是作为插值函数的参数, 注意:.attrs 方法只接受一个参数,即样式化组件的静态属性对象或者是一个返回属性对象的函数。
在平常开发中,通常有这么几种使用方式
- 设置默认属性 添加通用样式
export const MyInput = styled.input.attrs({
type: 'password',
style: {
padding: '10px'
}
})`
border: 1px red solid;
`
代码语言:javascript复制<MyInput></MyInput>
- 动态计算属性值
用函数属性来根据组件的 props 动态计算属性值。基于不同条件给组件添加属性值
代码语言:javascript复制export const MyButton = styled.button.attrs(props => ({
style: {
backgroundColor: props.variant === 'primary' ? 'blue' : 'gray'
}
}))
`
color: white;
padding: 10px 20px;
border: none;
cursor: pointer;
`
代码语言:javascript复制<MyButton variant='primary'>主题按钮</MyButton>
- 提供默认交互行为
export const MyButton = styled.button.attrs(props => ({
style: {
backgroundColor: props.variant === 'primary' ? 'blue' : 'gray'
},
onClick: () => console.log('Button clicked!'),
}))
`
color: white;
padding: 10px 20px;
border: none;
cursor: pointer;
`
代码语言:javascript复制<MyButton variant='primary'>主题按钮</MyButton>
多态属性(polymorphic prop) as
多态属性是指你可以在组件中通过一个属性来控制最终渲染的 HTML 元素类型或自定义组件类型。
比如我们写导航栏组件的时候,有些是菜单栏,有些是按钮,有些是链接,但所有的样式都相同,这时候我们可以通过这个多态属性来控制最终渲染成什么html标签或者自定义组件。
- 使用多态属性动态创建标签
export const Component = styled.div`
font-family: "Microsoft YaHei";
padding: 10px 10px;
line-height: 1;
-webkit-text-decoration: none;
text-decoration: none;
font-size: 14px;
background-color: blue;
color: white;
border: none;
box-sizing: border-box;
cursor: pointer;
`;
代码语言:javascript复制// 这个样式化组件最终会渲染成 a 标签
<Component as="a" href="https://www.baidu.com">button</Component>
<br/>
// 这个样式化组件最终会渲染成 button 标签
<Component
as="button"
onClick={() => alert('这是个按钮')}
>
button
</Component>
- 使用
forwardedAs
属性来传递被包裹组件的多态属性值。
如果一个组件被另一个或多个组件包裹着,外层组件可以通过 forwardedAs
属性来传递多态属(as
)性值到内部组件。
看下面例子:
代码语言:javascript复制export const Component = styled.button`
font-family: "Microsoft YaHei";
padding: 10px 10px;
line-height: 1;
-webkit-text-decoration: none;
text-decoration: none;
font-size: 14px;
background-color: blue;
color: white;
border: none;
box-sizing: border-box;
cursor: pointer;
`;
export const WrappedButton = (props) => {
return <div>
<Component {...props} />
</div>;
}
// 使用 styled() 高阶组件包装 Component,并传递 as 属性
const WrappedComponent = styled(WrappedButton)`
/* 这里可以添加额外样式 */
`;
代码语言:javascript复制<WrappedComponent forwardedAs="a" href="https://www.baidu.com">
Wrapped Link Button
</WrappedComponent>
控制属性传递(属性过滤器)
代码语言:javascript复制默认情况下,所有被包裹组件的属性值都会被传递到内部组件。而临时属性不会传递到最终渲染的 react 组件上。那假如我需要动态控制某些属性值能不能传递到最终渲染的 react 组件上时,就可以通过
shouldForwardProp
属性来控制。可以它当做一个属性过滤函数,类似Array.filter
方法。
export const Comp = styled('div').withConfig({
shouldForwardProp: (prop) => !['customProp'].includes(prop),
})`
color: ${props => props.color};
`;
代码语言:javascript复制 <Comp color='red' customProp="test">hello</Comp>
注意:这里面的变量color不能使用临时属性(带$的属性),临时属性的值是不会传递到最终渲染的组件上
下篇文章将介绍一些 styled component 的高阶组件,例如如何创建主题样式、如何获取主题样式、如何创建全局样式,如何创建动画等等。
写在最后
我是 AndyHu,目前暂时是一枚前端搬砖工程师。
文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注呀