Material UI 自定义 (TypeScript)

- 组件定制

我在这个项目中使用了多种自定义 Material UI 组件的方法:

  • 使用内联属性和样式:
import { Typography } from "@mui/material";

<Typography
  fontSize={18}
  fontWeight={600}
  style={{ textDecoration: "line-through" }}
>
  TEXT
</Typography>
import { Typography, SxProps, Theme } from "@mui/material";

const MyStyles: SxProps<Theme> = (theme: Theme) => ({
  mt: 7,
  fontSize: {
    xs: theme.typography.h4.fontSize,
    md: theme.typography.h3.fontSize,
  },
  fontWeight: 600,
});

<Typography sx={MyStyles}>TEXT</Typography>
  • 通过直接针对孩子的班级在父级上设置样式Mui

(在这个例子中"&>p"也可以工作,这个方法更适合其他组件Switch和类".MuiSwitch-thumb"

import { Box, Typography } from "@mui/material";

<Box
  sx={{ "&>.MuiTypography-root": { fontSize: 18, fontWeight: 600 } }}
>
  <Typography>Text</Typography>
</Box>
  • 在父项上设置样式并inherit在子项中使用

您可以将组件属性设置为具有“继承”的值,在这种情况下,它们会继承其父元素的样式。

import { Box, Typography } from "@mui/material";

<Box
  sx={{ fontSize: 18, fontWeight: 600 }}
>
  <Typography fontSize="inherit" fontWeight="inherit">
    Text
  </Typography>
</Box>
import { Typography, TypographyProps, styled() } from "@mui/material";

const CustomTypography = styled(Typography)<TypographyProps>(({ theme }) => ({
  fontSize: 18,
  fontWeight: 600,
  [theme.breakpoints.up("xs")]: {
    textAlign: "center",
  },
  [theme.breakpoints.up("md")]: {
    textAlign: "left",
  },
}));
  • 使用包装器组件:
import { Typography, TypographyProps } from "@mui/material";

const CustomTypography = (props: TypographyProps) => (
  <Typography
    fontSize={18}
    fontWeight="600"
    sx={{ textAlign: { xs: "center", md: "left" } }}
    {...props}
  >
    {props.children}
  </Typography>
);
  • styled()使用实用程序和包装器组件 的组合:
import { Link, LinkProps, styled() } from "@mui/material";

const CustomLink = (props: LinkProps) => {
  const MyLink = styled(Link)<LinkProps>(({ theme }) => ({
    color: "inherit",
    transition: theme.transitions.create(["color"], {
      duration: theme.transitions.duration.standard,
    }),
    "&:hover": {
      color: theme.palette.strongCyan.main,
    },
  }));
  return (
    <MyLink {...props} underline="none" rel="noopener">
      {props.children}
    </MyLink>
  );
};

- 主题

您可以通过更改/添加自定义颜色或palette设置默认使用的自定义字体来自定义 Material UI 主题。然后通过将您的组件包装在 a 中<ThemeProvider>theme子组件将可以使用:

import {
  ThemeProvider,
  createTheme,
  PaletteColor,
  SimplePaletteColorOptions,
} from "@mui/material/styles";

declare module "@mui/material/styles" {
  interface Palette {
    strongCyan: PaletteColor;
  }

  interface PaletteOptions {
    strongCyan: SimplePaletteColorOptions;
  }
}

const theme = createTheme({
  palette: {
    strongCyan: { main: "hsl(171, 66%, 44%)" },
  },
  typography: {
    fontFamily: "'Bai Jamjuree', 'sans-serif';",
  },
});

...

<ThemeProvider theme={theme}>
  <ChildComponent />
</ThemeProvider>

- CSS 重置/规范化

某些元素默认应用边距和填充值,这可能会弄乱布局。Material UI 提供了一个方便的组件,称为<CssBaseline>CSS Reset 并删除那些讨厌的默认样式:

import { CssBaseline } from "@mui/material";
...
<CssBaseline>
<YourOtherComponents />
</CssBaseline>

- 过渡

要向 Material UI 组件添加过渡效果,您可以使用theme.transitions.create()将要应用过渡效果的属性作为第一个参数并将设置对象作为第二个参数的函数。您可以将持续时间设置为主题中定义的值,以便在以后阶段轻松调整/更改:

sx={(theme) => ({
  transition: theme.transitions.create(
    ["color", "background-color"],
    {
      duration: theme.transitions.duration.standard,
    }
  ),
})}

- 媒体查询

Material UI 提供了一个方便的useMediaQuery()钩子,我们可以使用它来检测屏幕尺寸并执行诸如在特定屏幕尺寸上显示/隐藏组件之类的操作,或者在我的情况下,在较小的屏幕上禁用动画延迟。
你可以像这样使用它:

import { useMediaQuery, Theme } from "@mui/material";
...
const matches = useMediaQuery((theme: Theme) => theme.breakpoints.up("md"));

在这种情况下,matches如果屏幕大于md(中等)则为真,否则为假。然后你可以像使用任何其他boolean变量一样使用它来为你的逻辑/渲染添加条件。
您还可以使用精确的像素值:useMediaQuery('(min-width: 900px)')

- 自定义另一个组件的子组件

Material UI 中的某些组件内部还有其他嵌套组件。例如,一个组件内部Dialog有一个组件。Paper为了自定义嵌套组件的属性,它公开了一个名为的属性,PaperProps您可以使用它来执行此操作。您必须检查Material UI API才能了解每个组件的所有可用属性。

<Dialog
  PaperProps={{
    sx: {
      borderRadius: '1rem'
    },
  }}
>
...
</Dialog>

- 转发ref给子组件

有些组件Tooltip需要分配ref给它们的子组件才能正常工作,这意味着如果您将自定义组件放入组件中Tooltip,则必须React.forwardRef()与自定义组件一起使用,以便它接受一个refLink这就是我在自定义组件中实现自定义的方式Tooltip

import React from "react";
import { Link, Tooltip, LinkProps, TooltipProps } from "@mui/material";

// custom Tooltip wrapper component
const MyTooltip = (props: TooltipProps) => (
  <Tooltip
    {...props}
    arrow
    placement="top"
    TransitionComponent={Fade}
    TransitionProps={{ timeout: 500 }}
  >
    {props.children}
  </Tooltip>
);

// custom Link wrapper component
const MyLink = React.forwardRef<HTMLAnchorElement, LinkProps>(
  (props, ref) => {
    const linkStyles = (theme: Theme) => ({
      transition: theme.transitions.create(["filter", "transform", "border"], {
        duration: theme.transitions.duration.standard,
      }),
      "&:hover": {
        filter: "brightness(150%)",
        transform: "scale(1.2)",
      },
    });
    return (
      <Link {...props} target="_blank" rel="noopener" sx={linkStyles} ref={ref}>
        {props.children}
      </Link>
    );
  }
);

...

<MyTooltip title="React.js">
  <MyLink href="https://react.dev" target="_blank">
    React.js
  </MyLink>
</MyTooltip>

而不是
React.forwardRef<HTMLAnchorElement, LinkProps>(props, ref)
你可以使用
React.forwardRef((props: LinkProps, ref: React.Ref<HTMLAnchorElement>)

- 修改/合并sx属性

有时您需要使用sx已经定义的属性,但需要更改或删除其中的某些属性。有多种方法可以做到这一点:

sx1. 从prop 中移除属性

假设我们想从下面的 prop 中移除 backgroundColor sx

import { SxProps } from "@mui/material";

const myProp: SxProps = {
  color: "red",
  backgroundColor: "blue",
}
  • 使用扩展运算符
const {backgroundColor, ...myNewProp} = myProp;
  • 删除密钥
import { SystemCssProperties } from "@mui/system";

const myNewProp: SystemCssProperties = myProp;
delete myNewProp.backgroundColor;
  • 通过合并重置密钥

您可以通过将您的道具与另一个道具backgroundColor合并来重置该属性:合并将在下一节中解释。sx``sx``{backgroundColor: "transparent"}

sx2. 添加/修改道具 属性

  • 添加/修改密钥
myProp.backgroundColor = "green";
myProp.mt = 2;
  • 您还可以通过将您的样式与将添加/替换所需键的另一个样式合并来实现此目的。(接下来解释)

3.合并多个sx属性

  • 使用sx数组

sxprop 接受一个数组作为输入,它可以包含多个sx将合并在一起的属性:

<ComponentName sx={[{color: "red"},{backgroundColor: "blue"}]}  />
  • 使用Object.assign()

sx属性是对象,因此您可以使用[Object.assign()]将多个sx属性合并在一起:

const myNewProp: SxProps = Object.assign(myProp, {
  backgroundColor: "green",
});
  • 使用该merge-sx包 您可以使用mergeSx()该包提供的功能来合并多个sx属性。
npm install merge-sx
import { mergeSx } from "merge-sx";

const mySxProp1: SxProps = { ... }
const mySxProp2: SxProps = { ... }

const mySxProp3: SxProps = mergeSx(mySxProp1, mySxProp2);

这个包的好处是它SxProps也适用于函数式,我将在接下来解释。

4.处理功能sx属性

sx属性也可以是将作为theme输入并返回SxProps对象的函数:

import { SxProps, Theme } from "@mui/material";

const myStyles: SxProps<Theme> = (theme: Theme) => ({
  fontSize: {
    xs: theme.typography.h4.fontSize,
    md: theme.typography.h3.fontSize,
  },
});

这样您就可以在道具中使用主题中的变量sx
但这意味着您不能Object.assign()直接使用或修改键,因为您不再处理对象。
在这种情况下,最好的方法就是使用sx数组方法。一定要将主题sx也传递给功能属性。而且你还需要为你的sx道具​​使用更具体的类型:

import { SxProps, Theme } from "@mui/material";

// wrong type ("This expression is not callable." error)
const myStyle1 : SxProps<Theme> = (theme: Theme) => ({ ...

// correct type
import { SystemStyleObject } from "@mui/system";
type SxPropsFunc<T extends object> = (_: T) => SystemStyleObject<T>;
const myStyle1 : SxPropsFunc<Theme> = (theme: Theme) => ({...

// wrong ("No overload matches this call." error)
<Component sx={[myStyle1, myStyle2]} />

// correct
<Component
  sx={[
    (theme:Theme) => myStyle1(theme), 
    (theme:Theme) => myStyle2(theme)
  ]}
/>

弄清楚上面的正确类型花了很多时间…

总的来说,合并的时候,可以使用merge-sx前面提到的包,省去一些麻烦。你也可以传递主题:

import { SxProps, Theme } from "@mui/material";

const myStyles: SxProps<Theme> = (theme: Theme) => {...

<MyComponent
  sx={
    mergeSx<Theme>(
      (theme:Theme) => {
        fontSize: theme.typography.h4.fontSize
      },
      myStyles
    )
  }
/>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值