1 Star 2 Fork 0

fisher / flexstyled

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
readme_CN.md 13.22 KB
一键复制 编辑 原始数据 按行查看 历史
fisher 提交于 2024-05-24 17:55 . update

StyledFc

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

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

演示

安装

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} =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参数来指定styleIdclassName

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

嵌套样式

接下来我们来为Card组件的titlefooter添加样式.

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"
      }
  })
  • 以上我们为titlefooter添加了样式。
  • 使用&符号来表示当前父类元素,使用的方式与lesssass等嵌套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} =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变量。


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-colorcss变量。
  • 然后我们在title样式中使用了--primary-color变量。
  • getStyle函数支持传入更新css变量。

创建样式

styled函数也可以只用来创建样式并插入到HEAD

// card.style.ts

import { styled } from "styledfc"

// 创建样式并插入到head
export default styled({ // 组件样式
      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
      }
  })

// card.tsx
import cardStyle from "./card.style"

export default (props:CardProps)=>{
    return (
      <div className={cardStyle.className} style={cardStyle.getStyle({"--title-color":titleColor},props)}>
        <div className="title">            
            {props.title}
        </div>
        <div className="content">{props.children}</div>
        <div className="footer">{props.footer}</div>
      </div>
    )
  }

也可以使用 cardStyle.props简化参数传递,如下:

 
export default (props:CardProps)=>{
    return (
      <div {...cardStyle.props()}>
          ...
      </div>
    )
  }

// 当样式中包含css变量或者需要额外的样式时,可以使用如下方式传入

<div {...cardStyle.props({"--title-color":titleColor})}/>

// 如果使用了动态样式,则需要传入props参数
<div {...cardStyle.props({"--title-color":titleColor},{props})}/>
// 也可以传入额外的样式类名

<div {...cardStyle.props({"--title-color":titleColor},{props,className:"xxxxx xxxx"})}/>
  • 注意,如果使用到props动态样式,则getStyle需要传入props参数。

Hook

styledfc还提供了一个useStyled钩子,用于在函数组件中使用。

同样功能的Card组件可以使用useStyled钩子来实现。

import { useStyled } from "styledfc"
export const Card2:React.FC<React.PropsWithChildren<CardProps>> = ((props:CardProps)=>{
    const { title } = props
    const [titleColor,setTitleColor] = useState("blue")
    const {className,getStyle } =  useStyled({
        // 此处是组件样式
    })
    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>
    )
  })
  • useStyled钩子返回classNamegetStyle,用来注入样式类名和动态样式。
  • getStyle函数支持传入更新css变量。如果使用到props动态样式,则需要传入props参数。
  • useStyled钩子支持传入options参数来配置styleIdclassName
  • useStyledstyled函数功能一样,唯一的区别是useStyledhead注入的样式表在组件卸载时会自动移除。

创建样式组件

1.1.0版本开始,styledfc支持创建样式组件。


import { styled } from "styledfc"

const MyButton = styled.div({
    color:"red",
    "&:hover":{
        color:"blue"
    }
})

// 其他如styled.span,styled.button等任意有效的HTML tag

配置

styledfc支持以下options参数来配置。

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

性能

由于css-in-js的限制,可能会存在性能问题,一个推荐的性能优化方式是:在应用的启动阶段,将所有的样式一次性创建并插入到head中,然后在组件中来引用样式。

// styles.tsx
import { styled } from "styledfc"
export style1 = styled({...})
export style2 = styled({...})
export style3 = styled({...})

API

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)
styled<Props>(styles:CSSObject,options?:StyledOptions)
JavaScript
1
https://gitee.com/zhangfisher/flexstyled.git
git@gitee.com:zhangfisher/flexstyled.git
zhangfisher
flexstyled
flexstyled
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891