为啥我的 React 手风琴动画不起作用?
Posted
技术标签:
【中文标题】为啥我的 React 手风琴动画不起作用?【英文标题】:Why won't my React accordion animation work?为什么我的 React 手风琴动画不起作用? 【发布时间】:2018-03-20 20:17:37 【问题描述】:我在 React 中实现了我自己的响应式手风琴,我无法让它为折叠的打开设置动画。
这特别奇怪,因为我可以让标题前的图标上下动画,而且,除了图标是伪元素之外,我似乎看不出两者之间的区别。
JS:
class Accordion extends React.Component
constructor(props)
super(props);
this.state =
active: -1
;
/***
* Selects the given fold, and deselects if it has been clicked again by setting "active to -1"
* */
selectFold = foldNum =>
const current = this.state.active === foldNum ? -1 : foldNum;
this.setState(() => ( active: current ));
;
render()
return (
<div className="accordion">
this.props.contents.map((content, i) =>
return (
<Fold
key=`$i-$content.title`
content=content
handle=() => this.selectFold(i)
active=i === this.state.active
/>
);
)
</div>
);
class Fold extends React.Component
render()
return (
<div className="fold">
<button
className=`fold_trigger $this.props.active ? "open" : ""`
onClick=this.props.handle
>
this.props.content.title
</button>
<div
key="content"
className=`fold_content $this.props.active ? "open" : ""`
>
this.props.active ? this.props.content.inner : null
</div>
</div>
);
CSS:
$line-color: rgba(34, 36, 38, 0.35);
.accordion
width: 100%;
padding: 1rem 2rem;
display: flex;
flex-direction: column;
border-radius: 10%;
overflow-y: auto;
.fold
.fold_trigger
&:before
font-family: FontAwesome;
content: "\f107";
display: block;
float: left;
padding-right: 1rem;
transition: transform 400ms;
transform-origin: 20%;
color: $line-color;
text-align: start;
width: 100%;
padding: 1rem;
border: none;
outline: none;
background: none;
cursor: pointer;
border-bottom: 1px solid $line-color;
&.open
&:before
transform: rotateZ(-180deg);
.fold_content
display: none;
max-height: 0;
opacity: 0;
transition: max-height 400ms linear;
&.open
display: block;
max-height: 400px;
opacity: 1;
border-bottom: 1px solid $line-color;
这是 CodePen:https://codepen.io/renzyq19/pen/bovZKj
【问题讨论】:
避免为display
属性设置动画。 codepen.io/solbreslin/pen/QqmRLN -- 无法正常工作,但您可以通过删除 display
来查看高度过渡
【参考方案1】:
如果您想要平滑过渡,我不会有条件地呈现内容。这将使上滑动画变得特别棘手。
我会改变这个:
this.props.active ? this.props.content.inner : null
到这里:
this.props.content.inner
并使用这个scss
:
.fold_content
max-height: 0;
overflow: hidden;
transition: max-height 400ms ease;
&.open
max-height: 400px;
试试下面的 sn-p 或查看分叉的 CodePen Demo。
class Accordion extends React.Component
constructor(props)
super(props);
this.state =
active: -1
;
/***
* Selects the given fold, and deselects if it has been clicked again by setting "active to -1"
* */
selectFold = foldNum =>
const current = this.state.active === foldNum ? -1 : foldNum;
this.setState(() => ( active: current ));
;
render()
return (
<div className="accordion">
this.props.contents.map((content, i) =>
return (
<Fold
key=`$i-$content.title`
content=content
handle=() => this.selectFold(i)
active=i === this.state.active
/>
);
)
</div>
);
class Fold extends React.Component
render()
return (
<div className="fold">
<button
className=`fold_trigger $this.props.active ? "open" : ""`
onClick=this.props.handle
>
this.props.content.title
</button>
<div
key="content"
className=`fold_content $this.props.active ? "open" : ""`
>
this.props.content.inner
</div>
</div>
);
const pictures = [
"http://unsplash.it/200",
"http://unsplash.it/200",
"http://unsplash.it/200",
];
var test = (title, text, imageURLs) =>
const images=
<div className='test-images' >
imageURLs.map((url,i) => <img key=i src=url />)
</div>;
const inner =
<div className='test-content' >
<p>text </p>
images
</div>;
return title, inner;
;
const testData = [
test('Title', 'Content',pictures ),
test('Title', 'Content',pictures ),
test('Title', 'Content',pictures ),
test('Title', 'Content',pictures ),
test('Title', 'Content',pictures ),
];
ReactDOM.render(<Accordion contents=testData />, document.getElementById('root'));
.accordion
width: 100%;
padding: 1rem 2rem;
display: flex;
flex-direction: column;
border-radius: 10%;
overflow-y: auto;
.fold
border-bottom: 1px solid rgba(34, 36, 38, 0.35);
.fold .fold_trigger
text-align: start;
width: 100%;
padding: 1rem;
border: none;
outline: none;
background: none;
cursor: pointer;
border-bottom: 1px solid rgba(34, 36, 38, 0.35);
.fold .fold_trigger:before
font-family: FontAwesome;
content: "\f107";
display: block;
float: left;
padding-right: 1rem;
transition: transform 400ms;
transform-origin: 20%;
color: rgba(34, 36, 38, 0.35);
.fold .fold_trigger.open:before
transform: rotateZ(-180deg);
.fold .fold_content
max-height: 0;
overflow: hidden;
transition: max-height 400ms ease;
.fold .fold_content.open
max-height: 400px;
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<div id='root'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
注意:
我在过渡时使用了ease
而不是linear
,因为我认为它的效果更好。但这只是个人口味。 linear
也可以。
此外,您可以继续有条件地呈现内容。滑下动画是可能的,但上滑却不容易实现。您也可以探索一些transition libraries。
但是,我认为将状态仅用于条件类是最简单的(就像您对 open
类所做的那样)。如果您尝试制作 CSS 动画,我认为有条件地向 DOM 渲染内容会让您的生活变得困难。
【讨论】:
非常感谢!我注意到您还按照@ovokuro 的建议从CSS 中删除了display
。它会破坏转换吗?
没问题 :) 我很高兴它有帮助。以上是关于为啥我的 React 手风琴动画不起作用?的主要内容,如果未能解决你的问题,请参考以下文章