【发布时间】:2021-12-31 21:34:28
【问题描述】:
我正在尝试构建的是带有一些动画的垂直时间轴组件。我正在尝试的动画是它从第一个圆圈开始,无论哪个项目的状态为真,垂直线将从上到下绘制,同时无论哪个步骤完成,当线穿过它时,将从圆形变为完成复选标记。
如何实现上面的动画,到目前为止我已经尝试过但不知道如何实现上面的。
我想达到什么目的this
感谢任何帮助。
【问题讨论】:
标签: javascript css reactjs
我正在尝试构建的是带有一些动画的垂直时间轴组件。我正在尝试的动画是它从第一个圆圈开始,无论哪个项目的状态为真,垂直线将从上到下绘制,同时无论哪个步骤完成,当线穿过它时,将从圆形变为完成复选标记。
如何实现上面的动画,到目前为止我已经尝试过但不知道如何实现上面的。
我想达到什么目的this
感谢任何帮助。
【问题讨论】:
标签: javascript css reactjs
我已经修改了您的沙盒以使其正常工作:
https://codesandbox.io/s/animable-timeline-reactjs-tiofz
对于动画,我使用了以下 CSS:
div {
height: 200px;
width: 10px;
}
.green-progress {
background: linear-gradient(0, #00a36c, #00a36c) no-repeat, #ccc;
background-size: 100% 0;
animation: progressAnim 3s linear infinite forwards;
}
@keyframes progressAnim {
0% {
background-size: 100% 0;
}
100% {
background-size: 100% 100%;
}
}
<div class="green-progress"></div>
将App 转换为有状态组件,以便我们可以维护动画状态。
在构造函数中,为每个条目添加了id、startAnim 和checked 状态。在这里,我们将设置startAnim 标志以在相应的TimelineConnector 上启动动画。 checked 用于控制对圆圈的勾选。
在TimelineConnector 中,如果this.props.startAnim 为真,则将类设置为绿色进度。还添加了onAnimationEnd 处理程序作为{() => this.props.onAnimDone(this.props.id)}。这告诉 App 组件动画是在这个组件上用id 完成的。
在TimelineDot 中使用props.event.checked 设置检查状态。
在 App 中添加了一个生命周期钩子 componentDidMount,当所有组件都添加到实际 DOM 时,它将被调用。在钩子中,您选中第一个圆圈并在第一个 TimelineConnector 上启动动画。
当 TimelineConnector 完成动画后,它会在 App 中调用 startNextAnim。在该方法中,您首先完成最后一个条目的复选标记。如果条目有status:true,则开始下一个动画。
【讨论】:
你可以试试这个
/* timeline css */
@keyframes fill-color {
0% {
height: 0;
}
100% {
height: 100%;
}
}
@keyframes fill-color1 {
0% {
height: 0;
}
100% {
height: 50%;
}
}
@keyframes scaleup {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes fade {
0% {
color: rgba(black, 0.4);
}
100% {
color: rgba(black, 1);
}
}
body {
margin: 0;
padding: 0;
}
.timeline {
padding: 0;
list-style: none;
margin: 32px;
overflow: hidden;
position: relative;
}
.details {
margin-left: 48px;
border-bottom: 1px solid #f2f2f2;
min-height: 85px;
display: flex;
justify-content: center;
flex-direction: column;
}
.list,
.list-content {
position: relative;
width: 100%;
}
.list-content::before,
.list-content::after {
content: "";
display: block;
position: absolute;
left: 0;
transition: 0.2s all linear;
width: 0.714rem;
height: 0.714rem;
border-radius: 50%;
background-color: gray;
top: 50%;
z-index: 3;
margin-left: 0.35rem;
margin-top: rem(-8px);
}
.list-content::after {
z-index: 2;
}
.list {
position: relative;
width: 100%;
}
.list.active .list-content:before {
transform: scale(0);
width: 17px;
height: 17px;
border: 2px solid white;
background-color: red;
background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/White_check.svg/2048px-White_check.svg.png");
background-position: center;
background-repeat: no-repeat;
background-size: 9px 7px;
margin-left: 0;
margin-top: -8px;
animation: scaleup 0.4s forwards;
}
.list:before,
.list:after {
content: "";
display: block;
position: absolute;
left: 0;
transition: 0.2s all linear;
width: 0.214rem;
margin-left: 0.6rem;
}
.list:before {
background: #f2f2f2;
height: 100%;
}
.list:after {
background: red;
height: 0;
z-index: 1;
}
.list:before {
top: -50%;
}
.list.active:after {
top: 0;
animation: fill-color 0.4s forwards;
}
.list:last-child:after {
display: none;
}
.list:last-child.active:after {
display: block;
bottom: 50%;
animation: fill-color1 0.4s forwards;
}
.list:last-child .details {
border-bottom: none;
}
.list:first-child:before {
display: none;
}
.list:first-child.active:after {
animation: fill-color1 0.4s forwards;
top: 50%;
}
.list:first-child.active:after {
animation-delay: 1s;
}
.list:first-child.active .list-content:before {
animation-delay: 0.5s;
}
.list:nth-child(2).active:after {
animation-delay: 2s;
}
.list:nth-child(2).active .list-content:before {
animation-delay: 2s;
}
.list:nth-child(3).active:after {
animation-delay: 3s;
}
.list:nth-child(3).active .list-content:before {
animation-delay: 3s;
}
.list:nth-child(4).active:after {
animation-delay: 4s;
}
.list:nth-child(4).active .list-content:before {
animation-delay: 4.15s;
}
<body>
<ul class="timeline">
<li class="list active">
<div class="list-content">
<div class="details">
<h4 class="status-title">Step 1</h4>
</div>
</div>
</li>
<li class="list active">
<div class="list-content">
<div class="details">
<h4 class="status-title">Step 2</h4>
</div>
</div>
</li>
<li class="list active">
<div class="list-content">
<div class="details">
<h4 class="status-title">Step 3</h4>
</div>
</div>
</li>
<li class="list active">
<div class="list-content">
<div class="details">
<h4 class="status-title">Step 4</h4>
</div>
</div>
</li>
</ul>
</body>
您也可以查看Sandbox
在这里,我在所有 li 元素中添加了 active 类,但如果您想激活两个步骤,那么只应用前两个 li(即该类是有条件的)
【讨论】:
可以为背景设置动画。请检查下面的示例
.bg {
min-height: 300px;
width: 10px;
background: linear-gradient(0, red, red) no-repeat;
background-size: 100% 0;
animation: gradient 15s ease infinite;
}
@keyframes gradient {
0% {
background-size: 100% 0;
}
100% {
background-size: 100% 100%;
}
}
<div class="bg"></div>
您的 TimelineConnector 可以使用包含该 CSS 类的内容进行更新。
【讨论】: