介绍一个非常小巧优雅的css-in-js库

styledfc

一个简单的运行时css-in-js库,用于封装react组件

  • 零依赖
  • 非常小,<3kb.
  • 运行时生成css
  • 支持css变量
  • 支持类似less的嵌套css样式
  • 支持props动态css
  • 支持typescript

演示

安装

bash 复制代码
pnpm add styledfc
# or
npm install styledfc
# or
yarn add styledfc

用法

拟开发一个Card组件,组件有一个title属性,用于显示标题,一个footer属性,用于显示底部内容,children属性作为卡片的内容区。

基本用法

tsx 复制代码
import { styled } from "styledfc" 

export type  CardProps = React.PropsWithChildren<{
    title:string 
    footer?:string
  }>

export const Card = styled<CardProps>((props,{className})=>{
    const { title,children,footer} =props
    return (
      <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。

html 复制代码
<style id="6rxqfu">
.sw6y3s4{
    position:relative;
    width:100%;
    border:1px solid #ccc;
    border-radius:4px;
}
</style>

嵌套样式

接下来我们来为Card组件的title和footer添加样式.

tsx 复制代码
export const Card = styled<CardProps>((props,{className})=>{
    const { title,children,footer} =props
    return (
      <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生成的样式如下:

html 复制代码
<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属性来指定。

tsx 复制代码
export const Card = styled<CardProps>((props,{className,getStyle})=>{
    const { title,children,footer} =props
    return (
      <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变量。

tsx 复制代码
export const Card = styled<CardProps>((props,{className,getStyle})=>{
    const { title,children,footer} =props
    const [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钩子来实现。

tsx 复制代码
import { useStyle } from "styledfc"
export const Card2:React.FC<React.PropsWithChildren<CardProps>> = ((props:CardProps)=>{
    const { title } = props
    const [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参数来配置。

tsx 复制代码
// styled(<React.FC>,<styles>,<options>)
export interface StyledOptions{
    // 样式表的ID,没有指定则会自动生成
    styleId?:string                          
    // 生成的样式类名,如果没有指定则自动生成 
    className?:string                        
}

API

tsx 复制代码
export interface StyledOptions{
    // 生成的样式表id,如果没有指定则自动生成
    styleId?:string                          
    // 生成的css类名,如果没有指定则自动生成
    className?:string                
}
export type StyledComponentParams ={
    // 生成的css类名
    className:string
    // 生成的样式表id
    styleId: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.ReactElement

styled<Props>(FC: StyledComponent<Props>,styles:CSSObject,options?:StyledOptions)
相关推荐
原则猫1 小时前
UDP 到底怎么实现可靠的
前端
Java后端的Ai之路1 小时前
14、ReactJS - 路由(Router)
前端·react.js·状态模式
裕晟资质规划3 小时前
三类涉密资质延续时限差异分析:军工60日与集成印制3个月的边界
java·服务器·前端·网络·安全
ShineWinsu3 小时前
对于JavaScript:JavaScript基础语法的解析
开发语言·前端·javascript·面试·web·基础语法·循环
月夏3 小时前
Vue3 转 React:18 项对照表 + 5 个必踩的坑(附 7 天上手路线)
前端
广州华水科技3 小时前
单北斗GNSS位移监测系统的应用与维护解析
前端
梦曦i4 小时前
uni-storage 0.1.0 发布:TTL过期管理+多实例隔离
前端·storage·uni-app x
猫头_5 小时前
AI 流式传输工程指南:模型吐出半截 JSON,前端如何边收边渲染?
前端·javascript·llm
console.log('npc')5 小时前
第 1 章 项目概述与环境搭建
前端·人工智能·大模型
定栓5 小时前
Webpack迁到Vite第七节(二):全家桶移除 — Babel 全家桶深度分析
前端·webpack·node.js