如何使用 ReactCSSTransitionGroup 在 React 中为元素高度设置动画?
How to animate element height in React with ReactCSSTransitionGroup?
我正在尝试使用 ReactCSSTransitionGroup
为元素高度设置动画,
所以这就是我想要的动画效果:
http://jsfiddle.net/cherrry/hgk4Lme9/
问题是我并不总是知道元素的高度,
所以我试图在 componentDidMount
期间破解 scrollHeight
、clientHeight
或类似的东西,并尝试设置 node.style.height
或向样式表
添加规则
http://jsfiddle.net/cherrry/dz8uod7u/
离开动画很好看,但是元素进入的时候有点闪,缩放动画也很奇怪
应该是因为询问node.scrollHeight
导致渲染立即发生,所以有没有办法在动画开始之前获取相同的信息并注入css规则?还是我应该反过来想?
我对max-height
的解决方案不是很满意,因为当max-height
不接近或小于height
时,得到的动画速度会很奇怪,而且我的组件的高度差异很大。
我可以想象最终的解决方案可能有点混乱,
但我认为把它做成一个 Mixin 就足以在任何地方重用它了
经过更多的实验,我想出了一个解决方案,使用低级 API ReactTransitionGroup
而不是高级 ReactCSSTransitionGroup
这是带有有效解决方案的 JSFiddle:http://jsfiddle.net/cherrry/0wgp34cr/
在动画之前,它做了 3 件事:
- 获取计算出的高度、边距和边距
- 隐藏带有
display: none
的元素并添加.anim-enter
将高度设置为0
- 为
.anim-enter-active
创建 css 规则
要启动动画,它会做两件事:
- 取消隐藏元素
- 添加
.anim-enter-active
开始动画
JSFiddle 中的一些数字和 class 名称是硬编码的,但将 "mixin" 转换为 React class 以替代 [=11] 应该很容易=]
我遇到了同样的问题,最终编写了一个用于动画高度的独立组件。
你可以在这里看到演示:
https://stanko.github.io/react-animate-height/
它更容易使用,而且整个库真的很小(~200 行)
<AnimateHeight
duration={ 500 }
height={ 'auto' }
>
<h1>Your content goes here</h1>
<p>Put as many React or HTML components here.</p>
</AnimateHeight>
抱歉无耻的自我推销,但我认为如果你有多个组件需要制作动画,它可以为你节省很多时间。
干杯!
如果您不想导入模块或使用 qjuery,这里有一个使用 React ref 的模板 (https://reactjs.org/docs/refs-and-the-dom.html)
基本上你得到它的高度,增长到那个高度,切换回自动。在回来的路上切换到它的高度,然后回到 0.
class CollapsibleSectionBlock extends React.Component {
constructor(props) {
super(props);
this.state = {
showContent: false,
height: "0px",
myRef: null,
};
}
componentDidUpdate = (prevProps, prevState) => {
if (prevState.height === "auto" && this.state.height !== "auto") {
setTimeout(() => this.setState({ height: "0px" }), 1);
}
}
setInnerRef = (ref) => this.setState({ myRef: ref });
toggleOpenClose = () => this.setState({
showContent: !this.state.showContent,
height: this.state.myRef.scrollHeight,
});
updateAfterTransition = () => {
if (this.state.showContent) {
this.setState({ height: "auto" });
}
};
render() {
const { title, children } = this.props;
return (
<div>
<h2 onClick={() => this.toggleOpenClose()}>
{title}
</h2>
<div
ref={this.setInnerRef}
onTransitionEnd={() => this.updateAfterTransition()}
style={{
height: this.state.height,
overflow: "hidden",
transition: "height 250ms linear 0s",
}}
>
{children}
</div>
</div>
);
}
}
一个非常简单和好的方法是处理 scaleY 而不是高度。
悬停应该设置属性 transform: scaleY(1) (最初 => transform: scaleY(0) 隐藏它)并且动画应该以 transform 属性为目标。
我正在尝试使用 ReactCSSTransitionGroup
为元素高度设置动画,
所以这就是我想要的动画效果:
http://jsfiddle.net/cherrry/hgk4Lme9/
问题是我并不总是知道元素的高度,
所以我试图在 componentDidMount
期间破解 scrollHeight
、clientHeight
或类似的东西,并尝试设置 node.style.height
或向样式表
http://jsfiddle.net/cherrry/dz8uod7u/
离开动画很好看,但是元素进入的时候有点闪,缩放动画也很奇怪
应该是因为询问node.scrollHeight
导致渲染立即发生,所以有没有办法在动画开始之前获取相同的信息并注入css规则?还是我应该反过来想?
我对max-height
的解决方案不是很满意,因为当max-height
不接近或小于height
时,得到的动画速度会很奇怪,而且我的组件的高度差异很大。
我可以想象最终的解决方案可能有点混乱, 但我认为把它做成一个 Mixin 就足以在任何地方重用它了
经过更多的实验,我想出了一个解决方案,使用低级 API ReactTransitionGroup
而不是高级 ReactCSSTransitionGroup
这是带有有效解决方案的 JSFiddle:http://jsfiddle.net/cherrry/0wgp34cr/
在动画之前,它做了 3 件事:
- 获取计算出的高度、边距和边距
- 隐藏带有
display: none
的元素并添加.anim-enter
将高度设置为0 - 为
.anim-enter-active
创建 css 规则
要启动动画,它会做两件事:
- 取消隐藏元素
- 添加
.anim-enter-active
开始动画
JSFiddle 中的一些数字和 class 名称是硬编码的,但将 "mixin" 转换为 React class 以替代 [=11] 应该很容易=]
我遇到了同样的问题,最终编写了一个用于动画高度的独立组件。
你可以在这里看到演示: https://stanko.github.io/react-animate-height/
它更容易使用,而且整个库真的很小(~200 行)
<AnimateHeight
duration={ 500 }
height={ 'auto' }
>
<h1>Your content goes here</h1>
<p>Put as many React or HTML components here.</p>
</AnimateHeight>
抱歉无耻的自我推销,但我认为如果你有多个组件需要制作动画,它可以为你节省很多时间。
干杯!
如果您不想导入模块或使用 qjuery,这里有一个使用 React ref 的模板 (https://reactjs.org/docs/refs-and-the-dom.html)
基本上你得到它的高度,增长到那个高度,切换回自动。在回来的路上切换到它的高度,然后回到 0.
class CollapsibleSectionBlock extends React.Component {
constructor(props) {
super(props);
this.state = {
showContent: false,
height: "0px",
myRef: null,
};
}
componentDidUpdate = (prevProps, prevState) => {
if (prevState.height === "auto" && this.state.height !== "auto") {
setTimeout(() => this.setState({ height: "0px" }), 1);
}
}
setInnerRef = (ref) => this.setState({ myRef: ref });
toggleOpenClose = () => this.setState({
showContent: !this.state.showContent,
height: this.state.myRef.scrollHeight,
});
updateAfterTransition = () => {
if (this.state.showContent) {
this.setState({ height: "auto" });
}
};
render() {
const { title, children } = this.props;
return (
<div>
<h2 onClick={() => this.toggleOpenClose()}>
{title}
</h2>
<div
ref={this.setInnerRef}
onTransitionEnd={() => this.updateAfterTransition()}
style={{
height: this.state.height,
overflow: "hidden",
transition: "height 250ms linear 0s",
}}
>
{children}
</div>
</div>
);
}
}
一个非常简单和好的方法是处理 scaleY 而不是高度。 悬停应该设置属性 transform: scaleY(1) (最初 => transform: scaleY(0) 隐藏它)并且动画应该以 transform 属性为目标。