MUI 中的渐变动画效果

MUIReact 结合使用时,我们可以为页面中的组件设置折叠(Collapse)、淡入淡出(Fade)、拓展(Grow)以及滑动(Slide)在内的多种不同的动画效果。在本文中,我们通过多个组件的淡入淡出效果组合,来实现近似渐变的动画效果。

淡入淡出效果

MUI 基于底层的 react-transition-group 组件对几种常用动画效果进行了封装,比如 MUI 官方文档中提到的淡入淡出动画效果:

MUI 中默认的淡入淡出效果动画

对应的代码如下:

// ...
export default function SimpleFade() {
  const [checked, setChecked] = React.useState(false);

  const handleChange = () => {
    setChecked((prev) => !prev);
  };

  return (
    <Box sx={{ height: 180 }}>
      <FormControlLabel
        control={<Switch checked={checked} onChange={handleChange} />}
        label="Show"
      />
      <Box sx={{ display: 'flex' }}>
        <Fade in={checked}>{icon}</Fade>
        <Fade in={!checked}>{icon}</Fade>
      </Box>
    </Box>
  );
}

在上述示例中,我们通过按钮来控制两个 icon 的显示状态。但这里有一个问题,隐藏的 icon 组件也会占有对应的位置,使得在绘制 UI 界面时出现问题:

Firefox 调试模式的一张截图,显示了位于左侧的一个隐藏对象,和位于右侧的一个显示正常的对象,其中左侧的对象拥有调试器标尺
Firefox 的调试模式下,注意到第一个隐藏的 icon 对象也被渲染

这里需要注意的地方在于,需要将隐藏的对象设置为条件渲染(conditional rendering),才能使两个对象之间达到正确的“切换”效果:

// ...
      <Box sx={{ display: 'flex' }}>
        {checked && <Fade in={checked}>{icon}</Fade>}
        {!checked && <Fade in={!checked}>{icon}</Fade>}
      </Box>
// ...

实际上,使用这种方式实现的切换效果对于要隐藏的元素并没有“消失”效果,只对要切换到的元素添加了“渐入”效果。如果为 Fade 组件设置一个较短的 timeout 时间,则有助于在视觉上减小这种影响。

实际示例

我们以仿照 Google 登录界面为例,展示采用 MUI 中 Fade 效果的类似渐变的切换模式:

在上述示例中,我们使用了 Grid 容器对登录页面的两个状态(登录与注册)进行了管理,对于其中的每个组件(登录组件与注册组件),都设置了持续时长为 600 毫秒的渐入渐出动画效果:

<Grid item style={{ width: "95vw", maxWidth: "440px" }}>
  <Paper variant="outlined" style={{
      paddingLeft: "40px",
      paddingRight: "40px",
      paddingTop: "18px",
      paddingBottom: "18px",
      backgroundColor: "rgba(255, 255, 255, 0.75)" }}>
    <Fade in={!wishRegister} timeout={600}>
      <Box>{wishRegister === false ? <LoginPageLogin
        setUserToken={props.setUserToken}
        setWishRegister={setWishRegister}
        username={username}
        setUsername={setUsername}
        password={password}
        setPassword={setPassword}
      /> : null}</Box>
    </Fade>
    <Fade in={wishRegister} timeout={600}><Box>
      {wishRegister === true ? <LoginPageRegister
        setWishRegister={setWishRegister}
        username={username}
        setUsername={setUsername}
        password={password}
        setPassword={setPassword}
      /> : null}</Box></Fade>

    <Box style={{ height: "2vh" }} />
  </Paper>
</Grid>

LoginPageLoginLoginPageRegister 是两个包含登录与注册表单的自定义组件。上述示例使用了 Fade 动画组件进行切换,同时,也可以考虑使用 Slide 等动画实现类似的效果。