槽位样式(Slot Recipes)
了解如何使用槽位样式(slot recipes)为多部分组件设置样式。
概述
当您需要对组件的多个部分应用样式变体时,槽位样式(Slot Recipes)会非常方便。
一个槽位样式包含以下属性:
className
: 要附加到组件槽位的 className 前缀slots
: 要设置样式的组件部分数组base
: 每个槽位的基本样式variants
: 每个槽位的不同视觉样式defaultVariants
: 组件的默认变体compoundVariants
: 每个槽位的复合变体组合和样式覆盖。
定义样式
使用 defineSlotRecipe
标识函数来创建槽位样式。
checkbox.recipe.ts
import { defineSlotRecipe } from "@chakra-ui/react"
export const checkboxSlotRecipe = defineSlotRecipe({
slots: ["root", "control", "label"],
base: {
root: { display: "flex", alignItems: "center", gap: "2" },
control: { borderWidth: "1px", borderRadius: "sm" },
label: { marginStart: "2" },
},
variants: {
size: {
sm: {
control: { width: "8", height: "8" },
label: { fontSize: "sm" },
},
md: {
control: { width: "10", height: "10" },
label: { fontSize: "md" },
},
},
},
})
使用样式
有两种方式在组件中使用样式:
- 直接在组件中使用
useSlotRecipe
- 作为复合组件(推荐)使用
createSlotRecipeContext
useSlotRecipe
钩子或 createSlotRecipeContext
函数需要添加 "use client"
指令。这是因为它们底层依赖于 React 钩子,例如 useContext
和 useInsertionEffect
。直接在组件中
使用 useSlotRecipe
钩子获取组件的样式。然后,使用其变体属性调用样式以获取样式。
checkbox.tsx
"use client"
import { chakra, useSlotRecipe } from "@chakra-ui/react"
import { checkboxSlotRecipe } from "./checkbox.recipe"
export const Checkbox = (props) => {
const { size, ...restProps } = props
const recipe = useSlotRecipe({ recipe: checkboxSlotRecipe })
const styles = recipe({ size })
return (
<chakra.label css={styles.root}>
<chakra.input type="checkbox" css={styles.control} {...restProps} />
<chakra.span css={styles.label}>Checkbox Label</chakra.span>
</chakra.label>
)
}
splitVariantProps
请注意,size
属性是如何从属性中解构出来并传递给样式的。更智能的方法是自动将样式属性从组件属性中分离出来。
为此,请使用 recipe.splitVariantProps
函数将样式属性从组件属性中分离出来。
checkbox.tsx
"use client"
import { chakra, useSlotRecipe } from "@chakra-ui/react"
import { checkboxSlotRecipe } from "./checkbox.recipe"
export const Checkbox = (props) => {
const recipe = useSlotRecipe({ recipe: checkboxSlotRecipe })
const [recipeProps, restProps] = recipe.splitVariantProps(props)
const styles = recipe(recipeProps)
//...
}
TypeScript
要推断样式变体属性类型,请使用 RecipeVariantProps
类型助手。
checkbox.tsx
import type { RecipeVariantProps } from "@chakra-ui/react"
import { checkboxSlotRecipe } from "./checkbox.recipe"
type CheckboxVariantProps = RecipeVariantProps<typeof checkboxSlotRecipe>
export interface CheckboxProps
extends React.PropsWithChildren<CheckboxVariantProps> {}
创建复合组件
将样式传递给 createSlotRecipeContext
函数以创建槽位样式上下文。
然后,使用 withProvider
和 withContext
函数创建共享相同上下文的复合组件。
withProvider
和 withContext
键入泛型。此方法旨在优化 TypeScript 性能。自动推断虽然方便,但由于涉及类型的复杂性,会减慢 TypeScript 编译速度。checkbox.tsx
"use client"
import { createSlotRecipeContext } from "@chakra-ui/react"
import { checkboxSlotRecipe } from "./checkbox.recipe"
const { withProvider, withContext } = createSlotRecipeContext({
recipe: checkboxSlotRecipe,
})
interface CheckboxRootProps
extends HTMLChakraProps<
"label",
RecipeVariantProps<typeof checkboxSlotRecipe>
> {}
export const CheckboxRoot = withProvider<HTMLLabelElement, CheckboxRootProps>(
"label",
"root",
)
interface CheckboxControlProps extends HTMLChakraProps<"input"> {}
export const CheckboxControl = withContext<
HTMLInputElement,
CheckboxControlProps
>("input", "control")
interface CheckboxLabelProps extends HTMLChakraProps<"span"> {}
export const CheckboxLabel = withContext<HTMLSpanElement, CheckboxLabelProps>(
"span",
"label",
)
将变体属性传递给“根”组件以应用样式。
注意:根组件是使用 withProvider
函数的组件。
app.tsx
const App = () => {
return (
<CheckboxRoot size="md">
<CheckboxControl />
<CheckboxLabel />
</CheckboxRoot>
)
}
unstyled 属性
此方法支持使用 unstyled
属性来移除样式所应用的样式。
checkbox.tsx
<CheckboxRoot unstyled>
<CheckboxControl />
<CheckboxLabel />
</CheckboxRoot>
TypeScript
要推断样式变体属性类型,请使用 RecipeVariantProps
类型助手。
import type { RecipeVariantProps, UnstyledProp } from "@chakra-ui/react"
import { checkboxSlotRecipe } from "./checkbox.recipe"
type CheckboxVariantProps = RecipeVariantProps<typeof checkboxSlotRecipe>
export interface CheckboxProps
extends React.PropsWithChildren<CheckboxVariantProps>,
UnstyledProp {}
复合变体
使用 compoundVariants
属性定义一组基于其他变体组合应用的变体。
checkbox.recipe.ts
import { defineSlotRecipe } from "@chakra-ui/react"
export const checkboxRecipe = defineSlotRecipe({
slots: ["root", "control", "label"],
base: {},
variants: {
size: {
sm: {},
md: {},
},
visual: {
contained: {},
outline: {},
},
},
compoundVariants: [
{
size: "sm",
visual: "outline",
css: {
control: { borderWidth: "1px" },
label: { color: "green.500" },
},
},
],
})
定位槽位
在某些情况下,可能需要按 className 定位槽位。
- 在配置中设置
className
属性 - 命名约定是
${className}__${slot}
checkbox.recipe.ts
import { defineSlotRecipe } from "@chakra-ui/react"
export const checkboxRecipe = defineSlotRecipe({
className: "checkbox",
slots: ["root", "control", "label"],
base: {
root: {
bg: "blue.500",
_hover: {
"& .checkbox__label": { color: "white" },
},
},
},
})
主题使用
为了以可重用方式使用样式,将其移动到系统主题并将其添加到 theme.slotRecipes
属性。
在主题中使用样式时,无需添加 "use client"
指令。
theme.ts
import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"
import { checkboxSlotRecipe } from "./checkbox.recipe"
const config = defineConfig({
theme: {
slotRecipes: {
checkbox: checkboxSlotRecipe,
},
},
})
export default createSystem(defaultConfig, config)
TypeScript
使用 CLI 为样式生成类型。
npx @chakra-ui/cli typegen ./theme.ts
然后,在您的组件中导入生成的类型。
checkbox.tsx
import type { SlotRecipeProps, UnstyledProp } from "@chakra-ui/react"
export interface CheckboxProps
extends SlotRecipeProps<"checkbox">,
UnstyledProp {}
更新代码
如果您直接在组件中使用样式,请更新 useRecipe
以使用 key
属性从主题中获取样式。
checkbox.tsx
const Checkbox = () => {
- const recipe = useRecipe({ recipe: checkboxRecipe })
+ const recipe = useRecipe({ key: "checkbox" })
// ...
}
如果您创建复合组件,请更新 createSlotRecipeContext
以使用 key
属性。
checkbox.tsx
const { withProvider, withContext } = createSlotRecipeContext({
- recipe: checkboxRecipe,
+ key: "checkbox",
})