使用样式系统和样式组件创建一个高度可重复使用的按钮。
如果你曾经使用过Chakra UI或Material UI之类的组件库,你可能知道这些库有多么直观。我一直想创建像这些库公开的组件一样可复用的组件。今天,我们将创建我们自己的酷炫可复用按钮组件😎。
首先,让我们列出我们期望可重复使用按钮具备的功能。对我来说,我希望能够自定义颜色、字体、大小、间距、布局等等。
首先安装要用到的库,并简要介绍一下每个库的功能。styled-componentsstyled-components
是一个 CSS-in-JS 库,允许你在 JavaScript 中编写作用域限定于一个组件的 CSS。它可以说是 CSS 模块的继承者。我们来看一个如何使用 styled-components 的示例。
import styled from 'styled-components'
const Button = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
`
现在,无论何时您想使用该按钮,只需像常规反应组件一样导入它即可。styled-components 允许您传递 props 进行自定义,因此,例如,如果您想根据 prop 更改按钮的字体大小,您可以这样做。
import styled, { css } from 'styled-components'
const Button = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
${props => props.fontSize ? css`
font-size: props.fontSize;
`: ''}
`
当我们想要将自定义字体大小传递给此组件时,您可以这样做。
<Button fontSize='2rem'>My button</Button>
你可以想象一下,仅仅利用这个 API,我们就能构建动态组件。我喜欢这种构建组件的方式,但如果我们添加 styled-system,就能创建更加健壮的组件。
在使用 styled-system 之前,我们先来定义一下它是什么。根据其文档, styled-system 是一组实用函数,它们可以向 React 组件添加样式属性,并允许你基于全局主题对象控制样式,该对象包含字体比例、颜色和布局属性。styled-system 可以与 styled-components 之类的 CSS-in-JS 库配合使用。
让我们看一个基本的例子。
import styled from 'styled-components'
import { color } from 'styled-system'
const Box = styled.div`
${color}
`
现在,此组件将有两个可用的样式属性:color
设置前景色和bg
设置背景色。(您也可以使用backgroundColor
)。
<Box color="#eee" bg="orange">
Orange
</Box>
现在我们对 styled-components 和 styled-system 的工作原理有了基本的了解,让我们开始创建我们的<Button/>
组件。
import styled from 'styled-components'
import { color } from 'styled-system'
const Button = styled.button`
border: 0;
outline: 0;
${color}
`
这使我们能够像这样设置按钮的样式,
<Button color="white" backgroundColor="tomato">
Hello, world!
</Button>
添加间距和字体大小
import styled from 'styled-components'
import { color, space, fontSize } from 'styled-system'
const Button = styled.button`
border: 0;
outline: 0;
${color}
${space}
${fontSize}
`
现在您可以自定义填充、字体大小和边距。下面是如何使用按钮的示例。
<Button color="white" backgroundColor="tomato" px='2rem' mr='1rem' fontSize='2rem'>
Hello, world!
</Button>
正如你所见,我们的组件变得越来越实用,但你可能不想在使用它时传递所有这些 props。这时,默认 props 和主题就派上用场了。
让我们创建一个带有颜色的基本主题并将默认道具传递给我们的按钮。
import styled, { ThemeProvider } from 'styled-components'
import { color, space, fontSize } from 'styled-system'
const theme = {
colors: {
custom: '#444',
yellow: 'yellow'
}
}
const Button = styled.button`
border: 0;
outline: 0;
${color}
${space}
${fontSize}
`
Button.defaultProps = {
backgroundColor: 'blue'
}
const App = () => {
return (
<ThemeProvider theme={theme}>
<Button color='custom'>Styled Button</Button>
</ThemeProvider>
)
}
从这段代码可以看出,所有按钮的背景都是蓝色,因为我们将其作为默认属性传递了。将 bg 或 backgroundColor 属性传递给按钮将覆盖默认的 backgroundColor 属性。
对于按钮,我们通常希望传递 variant 属性来进一步自定义按钮。样式系统中的 buttonStyle 函数允许我们添加 variant 属性,这在我们扩展主题时非常有用。以下代码演示了这一点。
import styled, { ThemeProvider } from 'styled-components'
import { color, space, fontSize, buttonStyle } from 'styled-system'
const theme = {
colors: {
custom: '#444',
yellow: 'yellow'
},
buttons: {
primary: {
color: 'white',
backgroundColor: 'blue'
},
secondary: {
color: 'white',
backgroundColor: 'green'
}
}
}
const Button = styled.button`
border: 0;
outline: 0;
${color}
${space}
${fontSize}
${buttonStyle}
`
Button.defaultProps = {
variant: 'primary',
backgroundColor: 'blue'
}
const App = () => {
return (
<ThemeProvider theme={theme}>
<Button color='custom' variant='secondary'>Styled Button</Button>
</ThemeProvider>
)
}
添加自定义道具
如果你想给按钮传递一个像 size 这样的属性,让它变成 small、medium 或 large 呢?样式良好的样式系统允许我们通过 variant 函数来实现。下面是我们将所有这些功能组合在一起的最终代码。请注意,这只是一个基础按钮,你甚至可以根据需要添加更多功能。
import styled, { ThemeProvider } from 'styled-components'
import { color, space, fontSize, buttonStyle, variant } from 'styled-system'
const buttonSize = variant({
prop: 'size',
key: 'buttonSizes'
})
const theme = {
colors: {
custom: '#444',
yellow: 'yellow'
},
buttons: {
primary: {
color: 'white',
backgroundColor: 'blue'
},
secondary: {
color: 'white',
backgroundColor: 'green'
}
},
buttonSizes: {
small: {
fontSize: '15px',
padding: `7px 15px`
},
medium: {
fontSize: '18px',
padding: `9px 20px`
},
large: {
fontSize: '22px',
padding: `15px 30px`
}
}
}
const Button = styled.button`
border: 0;
outline: 0;
${color}
${space}
${fontSize}
${buttonStyle}
`
Button.defaultProps = {
variant: 'primary',
backgroundColor: 'blue',
size: 'medium'
}
const App = () => {
return (
<ThemeProvider theme={theme}>
<Button color='custom' variant='secondary' size='large'>Styled Button</Button>
</ThemeProvider>
)
}