Styled组件 #
基本概念 #
styled API 是 Emotion 提供的一种创建样式化组件的方式,语法与 styled-components 类似,让你可以创建带有样式的 React 组件。
基本用法 #
创建样式组件 #
jsx
import styled from '@emotion/styled'
const Button = styled.button`
padding: 12px 24px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
&:hover {
background-color: #0056b3;
}
`
function App() {
return <Button>Click me</Button>
}
支持的元素 #
styled 支持所有 HTML 元素:
jsx
import styled from '@emotion/styled'
const Container = styled.div`...`
const Title = styled.h1`...`
const Paragraph = styled.p`...`
const Input = styled.input`...`
const Link = styled.a`...`
const Image = styled.img`...`
const List = styled.ul`...`
const ListItem = styled.li`...`
Props 动态样式 #
基本用法 #
根据 props 动态设置样式:
jsx
import styled from '@emotion/styled'
const Button = styled.button`
padding: ${props => props.size === 'large' ? '16px 32px' : '8px 16px'};
font-size: ${props => props.size === 'large' ? '18px' : '14px'};
background-color: ${props => props.variant === 'primary' ? '#007bff' :
props.variant === 'danger' ? '#dc3545' : '#6c757d'};
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
`
function App() {
return (
<>
<Button variant="primary" size="large">Primary Large</Button>
<Button variant="danger" size="small">Danger Small</Button>
<Button>Default</Button>
</>
)
}
复杂逻辑 #
使用函数处理复杂的样式逻辑:
jsx
import styled from '@emotion/styled'
const getButtonColors = (variant) => {
const colors = {
primary: { bg: '#007bff', hover: '#0056b3' },
secondary: { bg: '#6c757d', hover: '#545b62' },
success: { bg: '#28a745', hover: '#1e7e34' },
danger: { bg: '#dc3545', hover: '#c82333' },
warning: { bg: '#ffc107', hover: '#e0a800' },
}
return colors[variant] || colors.secondary
}
const Button = styled.button`
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
transition: background-color 0.2s ease;
background-color: ${props => getButtonColors(props.variant).bg};
color: ${props => props.variant === 'warning' ? '#333' : 'white'};
&:hover {
background-color: ${props => getButtonColors(props.variant).hover};
}
`
应该转发 vs 不应该转发的 Props #
默认情况下,所有 props 都会传递给 DOM 元素。使用 shouldForwardProp 控制:
jsx
import styled from '@emotion/styled'
const Button = styled.button`
padding: ${props => props.$size === 'large' ? '16px 32px' : '8px 16px'};
background: ${props => props.$variant === 'primary' ? '#007bff' : '#6c757d'};
`, {
shouldForwardProp: (prop) => !prop.startsWith('$')
})
function App() {
return <Button $variant="primary" $size="large">Click</Button>
}
样式继承 #
扩展样式 #
基于已有组件扩展样式:
jsx
import styled from '@emotion/styled'
const Button = styled.button`
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
`
const PrimaryButton = styled(Button)`
background-color: #007bff;
color: white;
&:hover {
background-color: #0056b3;
}
`
const DangerButton = styled(Button)`
background-color: #dc3545;
color: white;
&:hover {
background-color: #c82333;
}
`
const OutlineButton = styled(Button)`
background-color: transparent;
border: 2px solid #007bff;
color: #007bff;
&:hover {
background-color: #007bff;
color: white;
}
`
覆盖样式 #
在扩展时覆盖原有样式:
jsx
import styled from '@emotion/styled'
const Card = styled.div`
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
`
const FeaturedCard = styled(Card)`
border: 2px solid gold;
box-shadow: 0 4px 8px rgba(255, 215, 0, 0.3);
&:hover {
box-shadow: 0 8px 16px rgba(255, 215, 0, 0.4);
}
`
样式化已有组件 #
样式化第三方组件 #
为第三方组件添加样式:
jsx
import styled from '@emotion/styled'
import { Link } from 'react-router-dom'
const StyledLink = styled(Link)`
color: #007bff;
text-decoration: none;
padding: 8px 16px;
border-radius: 4px;
&:hover {
background-color: #f0f0f0;
}
&.active {
background-color: #007bff;
color: white;
}
`
样式化自定义组件 #
jsx
import styled from '@emotion/styled'
const CustomButton = ({ className, children, onClick }) => (
<button className={className} onClick={onClick}>
{children}
</button>
)
const StyledCustomButton = styled(CustomButton)`
padding: 12px 24px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 25px;
cursor: pointer;
font-weight: bold;
&:hover {
opacity: 0.9;
}
`
as 属性 #
动态改变标签 #
使用 as 属性动态改变渲染的标签:
jsx
import styled from '@emotion/styled'
const Button = styled.button`
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
`
function App() {
return (
<>
<Button>Button</Button>
<Button as="a" href="/link">Link</Button>
<Button as={Link} to="/route">Router Link</Button>
</>
)
}
创建多态组件 #
jsx
import styled from '@emotion/styled'
const Text = styled.span`
font-size: ${props => props.size || '14px'};
font-weight: ${props => props.weight || 'normal'};
color: ${props => props.color || '#333'};
`
function App() {
return (
<>
<Text>Span</Text>
<Text as="p" size="16px">Paragraph</Text>
<Text as="h1" size="32px" weight="bold">Heading</Text>
<Text as="label" size="12px" color="#666">Label</Text>
</>
)
}
withComponent #
创建变体组件 #
使用 withComponent 基于相同样式创建不同标签的组件:
jsx
import styled from '@emotion/styled'
const Button = styled.button`
padding: 10px 20px;
background-color: #007bff;
color: white;
border-radius: 4px;
text-decoration: none;
display: inline-block;
`
const Link = Button.withComponent('a')
function App() {
return (
<>
<Button>Button</Button>
<Link href="/link">Link</Link>
</>
)
}
组合样式 #
使用 css 函数 #
组合多个样式:
jsx
import styled from '@emotion/styled'
import { css } from '@emotion/react'
const flexCenter = css`
display: flex;
align-items: center;
justify-content: center;
`
const cardStyle = css`
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`
const Card = styled.div`
${flexCenter}
${cardStyle}
padding: 20px;
min-height: 200px;
`
Mixin 模式 #
创建可复用的样式片段:
jsx
import styled from '@emotion/styled'
import { css } from '@emotion/react'
const mixins = {
flexCenter: css`
display: flex;
align-items: center;
justify-content: center;
`,
truncate: css`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`,
cardShadow: css`
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`,
smoothTransition: css`
transition: all 0.2s ease;
`,
}
const Card = styled.div`
${mixins.cardShadow}
${mixins.smoothTransition}
padding: 20px;
background: white;
border-radius: 8px;
&:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
`
const TruncatedText = styled.p`
${mixins.truncate}
max-width: 200px;
`
标签模板字面量 #
函数调用形式 #
除了模板字符串,还可以使用函数调用:
jsx
import styled from '@emotion/styled'
const Button = styled.button({
padding: '10px 20px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
})
混合使用 #
jsx
import styled from '@emotion/styled'
const Button = styled.button(
{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
},
props => ({
backgroundColor: props.primary ? '#007bff' : '#6c757d',
color: 'white',
})
)
最佳实践 #
1. 组件命名 #
使用语义化的组件名称:
jsx
const PrimaryButton = styled.button`...`
const CardContainer = styled.div`...`
const NavigationBar = styled.nav`...`
const UserAvatar = styled.img`...`
2. 样式组织 #
将相关组件放在一起:
jsx
const Card = styled.div`...`
const CardHeader = styled.div`...`
const CardBody = styled.div`...`
const CardFooter = styled.div`...`
3. 导出组件 #
从单独的文件导出样式组件:
jsx
export const Button = styled.button`...`
export const Card = styled.div`...`
export const Input = styled.input`...`
下一步 #
掌握了 styled API 后,继续学习 Props动态样式,深入了解动态样式的更多技巧。
最后更新:2026-03-28