Set*_*ske 4 typescript reactjs material-ui react-proptypes
我发现自己在 Material ui 中编写了一些通用组件,其中样式实际上是在父组件或祖父组件中定义的。例如:
const GenericDescendant = (props: DescendantProps) => {
const { classesFromAncestor, ...other } = props
return <Button className={classesFromAncestor} {...props}>Text here</Button>
}
Run Code Online (Sandbox Code Playgroud)
从祖先那里,我创建了一个useStylesandclasses对象并将其传递下来:
const useDescendantStyles = makeStyles({
selector: {
border: '1px solid green',
// more customized styles
}
})
const Ancestor = () => {
const descendantClasses = useDescendantStyles()
return <GenericDescendant classesFromAncestor={descendantClasses} />
}
Run Code Online (Sandbox Code Playgroud)
或者另一种方式,我可以用来withStyles包装后代中使用的组件:
const GenericDescendant = (props: DescendantProps) => {
const { tooltipClassesFromAncestor, buttonClassesFromAncestor, ...other } = props
const CustmoizedTooltip = withStyles(tooltipClassesFromAncestor)(Tooltip);
const CustomButton = withStyles(buttonClassesFromAncestor)(Button)
return (
<CustmoizedTooltip>
<CustomButton>Text here</CustomButton>
</CustmoizedTooltip>
)
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我不会调用useStylesAncestor,我只会像这样传递对象:
const Ancestor = () => {
return <GenericDescendant classesFromAncestor={{
selector: {
border: '1px solid green',
// more customized styles
}
}} />
}
Run Code Online (Sandbox Code Playgroud)
我不想将整个组件包装GenericDescendant在 a 中withStyles,因为这样我就无法确定哪个组件正在采用从祖先传递的自定义样式。
这些情况略有不同,但我可以采用任一途径来允许自定义祖先的通用后代。但是,当将自定义样式作为道具传递时,我不知道如何classesFromAncestor在DescendantProps. 它实际上可以采取任何形式,并且该形式直到运行时才会被知道。我不想将其输入为any. 定义作为 prop 传递的类类型的最佳方法是什么?
我一直在玩这个,有很多可能的设置。您可以通过传递单个元素来设置material-ui组件的样式,也可以传递一个与该组件可用的不同选择器相对应的string className对象。classes大多数(但不是全部)Material 组件的主要选择器是root。AButton接受类、、root和许多其他类。labeltext
当您调用makeStyles您创建的内容object时,键是选择器,基本上与您的输入相同的键,值是string生成的类的类名称。您可以将此类型导入为ClassNameMapfrom @material-ui/styles。它本质上是Record<string, string>,但有一个可选的泛型,可以让您限制键。
export type ClassNameMap<ClassKey extends string = string> = Record<ClassKey, string>;
Run Code Online (Sandbox Code Playgroud)
makeStyles您传递给or的第一个参数withStyles是样式属性的键控对象。它可以简化为,Record<string, CSSProperties>或者您可以从material-ui导入复杂类型,其中包括对函数的支持等。该类型Styles<Theme, Props, ClassKey>采用三个可选泛型,其中Theme是主题的类型,Props是组件自己的道具,也是ClassKey受支持的选择器。 Theme和主要包含在内,以便您可以将样式映射为或 的Props函数。themeprops
如果我们想同时向多个组件提供样式,一种简单的方法是为每个组件创建一个带有一个键的样式对象。你可以随意称呼它们。然后我们将每个样式作为 传递className给组件。
const MyStyled = withStyles({
button: {
border: "green",
background: "yellow"
},
checkbox: {
background: "red"
}
})(({ classes }: { classes: ClassNameMap }) => (
<Button className={classes.button}>
<Checkbox className={classes.checkbox} />
Text Here
</Button>
));
Run Code Online (Sandbox Code Playgroud)
该设置允许任意数量的组件处于任意级别的嵌套。
我尝试了制作一个可以包裹外部组件的高阶组件。您可以使用它作为起点,并根据您的需要进行调整。
const withAncestralStyles = <Props extends { className?: string } = {}>(
Component: ComponentType<Props>,
style: Styles<DefaultTheme, Omit<Props, "children">, string>
) => {
const useStyles = makeStyles(style);
return (
props: Omit<Props, "children"> & {
children?: (styles: ClassNameMap) => ReactNode;
}
) => {
console.log(props);
const classes = useStyles(props);
const { children, className, ...rest } = props;
return (
<Component {...rest as Props} className={`${className} ${classes.root}`}>
{children ? children(classes) : undefined}
</Component>
);
};
};
Run Code Online (Sandbox Code Playgroud)
基本上,该类classes.root将自动应用于className父级,而所有样式都作为道具传递给子级(但不应用)。我在React.cloneElement工作中遇到了麻烦,所以我要求children组件的 是function接收classes对象的。
const StyledButton = withAncestralStyles(Button, {
root: {
border: "green",
background: "yellow"
},
checkbox: {
background: "red"
}
});
const MyComponent = () => (
<StyledButton onClick={() => alert('clicked')}>
{(classes) => <><Checkbox className={classes.checkbox}/>Some Text</>}
</StyledButton>
);
Run Code Online (Sandbox Code Playgroud)
此方法无法在您的Tooltip示例中正常工作,因为Tooltip它是没有root选择器的组件之一,需要采用不同的样式来定位弹出窗口。
| 归档时间: |
|
| 查看次数: |
5762 次 |
| 最近记录: |