StyledFc
一个简单的运行时css-in-js
库,用于封装react
组件
- 零依赖
- 非常小,< 3kb.
- 运行时生成css
- 支持css变量
- 支持类似less的嵌套css样式
- 支持props动态css
- 支持typescript
在线演示 | Github
安装
pnpm add styledfc
# or
npm install styledfc
# or
yarn add styledfc
用法
拟开发一个Card
组件,组件有一个title
属性,用于显示标题,一个footer
属性,用于显示底部内容,children
属性作为卡片的内容区。
基本用法
import { styled } from "styledfc" export type CardProps = React.PropsWithChildren<{title:string footer?:string}>export const Card = styled<CardProps>((props,{className})=>{const { title,children,footer} =propsreturn (<div className={className}><div className="title"> {title}</div><div className="content">{children}</div><div className="footer">{footer}</div></div>)},{ // 组件样式position:"relative",width:"100%",border:"1px solid #ccc",borderRadius:"4px" })
- 以上代码将创建一个
Card
组件,为样式生成一个样式类(名称是随机生成的)并插入到head
标签中。 - 然后将
className
属性传递给组件,组件将使用这个类名来应用样式。
实际上,你可以在head
发现一个类似这样的CSS
样式,其中的类名
和style.id
均是自动生成的。也可以通过options
参数来指定styleId
和className
。
<style id="6rxqfu">
.sw6y3s4{position:relative;width:100%;border:1px solid #ccc;border-radius:4px;
}
</style>
嵌套样式
接下来我们来为Card
组件的title
和footer
添加样式.
export const Card = styled<CardProps>((props,{className})=>{const { title,children,footer} =propsreturn (<div className={className}><div className="title"> {title}</div><div className="content">{children}</div><div className="footer">{footer}</div></div>)},{ // 组件样式position:"relative",width:"100%",border:"1px solid #ccc",borderRadius:"4px","& > .title":{fontSize:"20px",fontWeight:"bold",},"& > .footer":{borderTop:"1px solid #ccc",padding:"8px",textAlign:"right"}})
- 以上我们为
title
和footer
添加了样式。 - 使用
&
符号来表示当前父类元素,使用的方式与less
和sass
等嵌套CSS的语法类似。
在head
生成的样式如下:
<style id="6rxqfu">
.sw6y3s4{position:relative;width:100%;border:1px solid #ccc;border-radius:4px;
}
.sw6y3s4 > .title{font-size:20px;font-weight:bold;
}
.sw6y3s4 > .footer{border-top:1px solid #ccc;padding:8px;text-align:right;
}
</style>
动态样式
styledfc
支持使用props
来动态设置样式。
我们想让卡片content
的背景颜色可以通过props.bgColor
属性来指定。
export const Card = styled<CardProps>((props,{className,getStyle})=>{const { title,children,footer} =propsreturn (<div className={className} style={getStyle()}><div className="title"> {title}</div><div className="content">{children}</div><div className="footer">{footer}</div></div>)},{ // 组件样式position:"relative",width:"100%",border:"1px solid #ccc",borderRadius:"4px","& > .title":{fontSize:"20px",fontWeight:"bold",},"& > .footer":{borderTop:"1px solid #ccc",padding:"8px",textAlign:"right"},"& > .content":{padding:"8px",backgroundColor:(props)=>props.bgColor}})
- 为了支持动态属性,我们需要使用
getStyle
函数来获取动态样式,然后注入到组件的根元素中。 getStyle
函数返回一个css
样式对象,可以直接传递给style
属性。- 任意
css
属性均可以使用(props)=>{....}
来动态生成CSS属性值。
CSS变量
styledfc
支持使用css
变量。可以在getStyle
函数中传入更新后的css
变量。
export const Card = styled<CardProps>((props,{className,getStyle})=>{const { title,children,footer} =propsconst [primaryColor,setPrimaryColor] = React.useState("blue")return (<div className={className} style={getStyle({"--primary-color":primaryColor})}><div className="title"> {title}<button onClick={()=>setPrimaryColor('red')}></div><div className="content">{children}</div><div className="footer">{footer}</div></div>)},{ // 组件样式position:"relative",width:"100%",border:"1px solid #ccc",borderRadius:"4px","--primary-color":"blue","& > .title":{fontSize:"20px",fontWeight:"bold",color:"var(--primary-color)"},"& > .footer":{borderTop:"1px solid #ccc",padding:"8px",textAlign:"right"},"& > .content":{padding:"8px",backgroundColor:(props)=>props.bgColor}})
- 以上我们在根样式中声明了一个
--primary-color
的css
变量。 - 然后我们在
title
样式中使用了--primary-color
变量。 getStyle
函数支持传入更新css
变量。
小结
- 默认只需要在组件引用
className
即可。 - 如果需要使用
props
动态css
属性,需要使用getStyle
函数来获取动态css
样式并注入到根元素中。 getStyle
函数支持传入更新css
变量。
Hook
styledfc
还提供了一个useStyle
钩子,用于在函数组件中使用。
同样功能的Card
组件可以使用useStyle
钩子来实现。
import { useStyle } from "styledfc"
export const Card2:React.FC<React.PropsWithChildren<CardProps>> = ((props:CardProps)=>{const { title } = propsconst [titleColor,setTitleColor] = useState("blue")const {className,getStyle } = useStyle({// 此处是组件样式})return (<div className={className} style={getStyle({"--title-color":titleColor},props)}><div className="title"> <span>{title}</span><span className="tools"><button onClick={()=>setTitleColor(getRandColor())}>Change</button></span></div><div className="content"> {props.children}</div><div className="footer">{props.footer}</div></div>)})
useStyle
钩子返回className
和getStyle
,用来注入样式类名和动态样式。getStyle
函数支持传入更新css
变量。如果使用到props
动态样式,则需要传入props
参数。useStyle
钩子支持传入options
参数来配置styleId
和className
。useStyle
与styled
函数功能一样,唯一的区别是useStyle
在head
注入的样式表在组件卸载时会自动移除。
配置
styledfc
支持以下options
参数来配置。
// styled(<React.FC>,<styles>,<options>)
export interface StyledOptions{// 样式表的ID,没有指定则会自动生成styleId?:string // 生成的样式类名,如果没有指定则自动生成 className?:string
}
API
export interface StyledOptions{// 生成的样式表id,如果没有指定则自动生成styleId?:string // 生成的css类名,如果没有指定则自动生成className?:string
}
export type StyledComponentParams ={// 生成的css类名className:string// 生成的样式表idstyleId:string// css变量vars:Record<string,string | number> // 获取动态css样式,当使用props动态css时需要使用getStyle注入css样式对象,例如style={getStyle()}getStyle : ()=>Record<string,string | number>
}export type StyledComponent<Props> = (props:React.PropsWithChildren<Props>,params:StyledComponentParams)=>React.ReactElementstyled<Props>(FC: StyledComponent<Props>,styles:CSSObject,options?:StyledOptions)
在线演示 | Github