使用水平 MUI Collapse Component 和 Transition Group 过渡时如何使 Flexbox 与子项一起工作?

How to make Flexbox work with children when using horizontal MUI Collapse Component and TransitionGroup transitions?

我正在使用 MUI,但在使用 Collapse + TransitionGroup 组件和使用 flex box 扩展容器时遇到了困难。

<Box sx={{display: 'flex', height: '100vh', width: '100vw'}}>
  <Box sx={{flex: 1}}>Content-A</Box>
  <Box sx={{flex: 1}}>Content-B</Box>
</Box>

这是我想要的一个简单示例。两个框彼此相邻,将整个页面分成左侧和右侧。但是,当您引入折叠组件时,它会中断:

<TransitionGroup sx={{display: 'flex', height: '100vh', width: '100vw}}>
  <Collapse orientation='horizontal'>
    <Box sx={{flex: 1}}>Content-A</Box>
  </Collapse>
  <Collapse orientation='horizontal'>
    <Box sx={{flex: 1}}>Content-B</Box>
  </Collapse>
</TransitionGroup>

Collapse 组件现在直接干扰 Flexbox 父子关系。如果查看 DOM,我会注意到 Collapse Component 在子组件周围插入了 3 个包装器(root、outer、inner wrap)。如何将 flexbox 属性传递给原始子项?
我尝试重写主题中每个包装组件的样式,并给它们 display: flex, flex: 1 以强制它一直沿着链向下传递到子元素,但这会破坏过渡,看起来超级不稳定。

编辑: 澄清一下:我需要过渡组,因为我希望发生特定的过渡。基本上我将页面分成左 (A) 和右 (B)。在一个事件中,我希望 (A) 过渡出屏幕(向左,因此是水平的)。 (B) 应该过渡到 (A) 所在的位置,并且新元素 (C) 从右侧进入并过渡到 (B) 所在的位置。想象它就像一个滑动队列。然后冲洗并重复(B out -> C 转到 B 所在的位置 -> D 过渡到 C 所在的位置)。问题是使用 Collapse horizo​​ntal 它不会弯曲剩余的 space.

我认为 css flex<Collapse /> 不应该以这种方式使用。 <Collapse /> 本身会将 css 设置为 width:0px,而您的 display:flex 将忽略它。

使用 CSSTransition

作为替代方案,您可以使用 <CSSTransition /> 组件自行创建和设置转换规则。 这也被 <Collapse/> 内部使用。

docs 应该会有帮助。

例子

有个sandbox example

const useStyles = makeStyles({
  "slide-enter": {
    flexGrow: 0,
    width: 0,
    overflow: "hidden",
    whiteSpace: "nowrap",
    transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms"
  },
  "slide-active-enter": {
    flexGrow: 1,
    width: "auto",
    overflow: "hidden",
    whiteSpace: "nowrap",
    transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms"
  },
  "slide-done-enter": {
    flexGrow: 1,
    width: "auto",
    overflow: "hidden",
    whiteSpace: "nowrap"
  },
  "slide-exit": {
    flexGrow: 1,
    width: "auto",
    transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms"
  },
  "slide-active-exit": {
    flexGrow: 0,
    width: 0,
    overflow: "hidden",
    whiteSpace: "nowrap",
    paddingLeft: 0,
    paddingRight: 0,
    transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms"
  },
  "slide-done-exit": {
    flexGrow: 0,
    width: 0,
    overflow: "hidden",
    whiteSpace: "nowrap",
    paddingLeft: 0,
    paddingRight: 0
  }
});

.......
     <TransitionGroup style={{ display: "flex" }}>
        {columns.map((_, i) =>
          i >= columns.length - 2 ? (
            <CSSTransition
              key={i}
              timeout={300}
              classNames={{
                appear: classes["slide-enter"],
                appearActive: classes["slide-active-enter"],
                appearDone: classes["slide-done-enter"],
                enter: classes["slide-enter"],
                enterActive: classes["slide-active-enter"],
                enterDone: classes["slide-done-enter"],
                exit: classes["slide-exit"],
                exitActive: classes["slide-active-exit"],
                exitDone: classes["slide-done-exit"]
              }}
            >
              <ColoredBox>Content-{i}</ColoredBox>
            </CSSTransition>
          ) : null
        )}
      </TransitionGroup>

旧答案

OP 澄清之前的旧答案:
有点不清楚您实际想要实现的目标。

为什么要使用过渡组?

通常 <TransistionGroup /> 用于在 <Collapse/> 上自动设置 in 属性。例如在列表中添加一堆项目时。

如果您只想呈现 2 列,则不需要 <TransistionGroup />
您可以手动传递 in 布尔值。

设计崩溃的样式。

您可以将样式传递给折叠包装器并设置您需要的任何 css。 即:

       <Collapse
          in={isOn}
          orientation="horizontal"
          style={{ flex: "1", display: "inline-block" }}
        >

例子

看看这个Code sandbox

它有 2 个示例:

  • 版本 1 只是 open/close 列
  • 添加列并使用 transitiongroup 扩展它们的版本 2

我认为版本 1 是您真正想要的:

const Example1 = () => {
  const [isOn, setIsOn] = React.useState(false);

  const toggle = () => {
    setIsOn((prev) => !prev);
  };

  return (
    <>
      <Button variant="contained" onClick={toggle}>
        {isOn ? "collapse" : "expand"}
      </Button>

      <Box display="flex">
        <Collapse
          in={isOn}
          orientation="horizontal"
          style={{ flex: "1", display: "inline-block" }}
        >
          <Box>Content-A</Box>
        </Collapse>
        <Collapse
          in={isOn}
          orientation="horizontal"
          style={{ flex: "1", display: "inline-block" }}
        >
          <Box>Content-B</Box>
        </Collapse>
      </Box>
    </>
  );
};