配方
使用 Chakra 中的配方编写多变体样式。
概述
Chakra 提供了一种编写 CSS-in-JS 的方式,具有更好的性能、开发体验和可组合性。其关键特性之一是能够使用类型安全的运行时 API 创建多变体样式。
一个配方包含以下属性
className
:要附加到组件的 classNamebase
:组件的基础样式variants
:组件的不同视觉样式compoundVariants
:组件的变体不同组合defaultVariants
:组件的默认变体值
定义配方
使用 defineRecipe
标识函数来创建配方。
button.recipe.ts
import { defineRecipe } from "@chakra-ui/react"
export const buttonRecipe = defineRecipe({
base: {
display: "flex",
},
variants: {
visual: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
})
使用配方
有两种方式可以在组件中使用配方
- 直接在组件中使用
useRecipe
- 使用
chakra
工厂创建组件(推荐)
useContext
和 useInsertionEffect
这样的 React 钩子,因此需要添加 "use client"
指令。直接在组件中
使用 useRecipe
钩子来获取组件的配方。然后,使用其变体属性调用配方以获取样式。
button.tsx
"use client"
import { chakra, useRecipe } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = (props) => {
const { visual, size, ...restProps } = props
const recipe = useRecipe({ recipe: buttonRecipe })
const styles = recipe({ visual, size })
return <chakra.button css={styles} {...restProps} />
}
splitVariantProps
请注意,visual
和 size
属性是如何从要传递给配方的属性中解构出来的。一个更智能的方法是自动将配方属性从组件属性中分离出来。
为此,使用 recipe.splitVariantProps
函数将配方属性从组件属性中分离出来。
button.tsx
"use client"
import { chakra, useRecipe } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = (props) => {
const recipe = useRecipe({ recipe: buttonRecipe })
const [recipeProps, restProps] = recipe.splitVariantProps(props)
const styles = recipe(recipeProps)
// ...
}
TypeScript
要推断配方变体属性类型,请使用 RecipeVariantProps
类型助手。
button.tsx
import type { RecipeVariantProps } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>
export interface ButtonProps
extends React.PropsWithChildren<ButtonVariantProps> {}
创建组件
使用 chakra
函数从配方创建组件。
注意:配方也可以内联到 chakra
函数中。
button.tsx
"use client"
import { chakra } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = chakra("button", buttonRecipe)
接下来,使用该组件并向其传递配方属性。
app.tsx
import { Button } from "./button"
const App = () => {
return (
<Button visual="solid" size="lg">
Click Me
</Button>
)
}
默认变体
defaultVariants
属性用于设置配方的默认变体值。这在您希望默认应用某个变体时很有用。
button.tsx
"use client"
import { chakra } from "@chakra-ui/react"
const Button = chakra("button", {
base: {
display: "flex",
},
variants: {
visual: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
defaultVariants: {
visual: "solid",
size: "lg",
},
})
复合变体
使用 compoundVariants
属性定义一组基于其他变体组合应用的变体。
button.tsx
"use client"
import { chakra } from "@chakra-ui/react"
const button = cva({
base: {
display: "flex",
},
variants: {
visual: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
compoundVariants: [
{
size: "small",
visual: "outline",
css: {
borderWidth: "2px",
},
},
],
})
当您同时使用 size="small"
和 visual="outline"
变体时,compoundVariants
将把 css
属性应用于组件。
app.tsx
<Button size="small" visual="outline">
Click Me
</Button>
注意事项
由于设计限制,将 compoundVariants
与响应式值一起使用不起作用。
这意味着这样的代码将无法工作
<Button size={{ base: "sm", md: "lg" }} visual="outline">
Click Me
</Button>
对于这些情况,我们建议渲染组件的多个版本,使用不同的断点,然后根据需要进行隐藏/显示。
主题使用
要以可重用方式使用配方,请将其移动到系统主题并添加到 theme.recipes
属性。
theme.ts
import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
const config = defineConfig({
theme: {
recipes: {
button: buttonRecipe,
},
},
})
export default createSystem(defaultConfig, config)
TypeScript
使用 CLI 为配方生成类型。
npx @chakra-ui/cli typegen ./theme.ts
然后,在您的组件中导入生成的类型。
button.tsx
import type { RecipeVariantProps } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>
export interface ButtonProps
extends React.PropsWithChildren<ButtonVariantProps> {}
更新代码
如果您直接在组件中使用配方,请更新 useRecipe
以使用 key
属性从主题中获取配方。
button.tsx
const Button = () => {
- const recipe = useRecipe({ recipe: buttonRecipe })
+ const recipe = useRecipe({ key: "button" })
// ...
}