使用水平 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 horizontal 它不会弯曲剩余的 space.
我认为 css flex
和 <Collapse />
不应该以这种方式使用。
<Collapse />
本身会将 css 设置为 width:0px
,而您的 display:flex
将忽略它。
使用 CSSTransition
作为替代方案,您可以使用 <CSSTransition />
组件自行创建和设置转换规则。
这也被 <Collapse/>
内部使用。
docs 应该会有帮助。
例子
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>
</>
);
};
我正在使用 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 horizontal 它不会弯曲剩余的 space.
我认为 css flex
和 <Collapse />
不应该以这种方式使用。
<Collapse />
本身会将 css 设置为 width:0px
,而您的 display:flex
将忽略它。
使用 CSSTransition
作为替代方案,您可以使用 <CSSTransition />
组件自行创建和设置转换规则。
这也被 <Collapse/>
内部使用。
docs 应该会有帮助。
例子
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>
</>
);
};