javascript - Javascript添加/删除动画类,只动画一次
问题描述
试图构建一个时间选择器,它应该动画输入的变化。我想我会通过在 CSS 中添加和删除动画类来做到这一点。问题是,它只在第一次工作。
我尝试设置一个开始的时间间隔,在一定时间后删除该类,略高于动画持续时间,但是每次点击都会减少动画的动画时间,并且通过第三次或第四次点击,它没有更长的动画。
然后我只是选择检查该类是否存在开始,删除它开始,然后添加它。确保每次都从头开始。但现在它只在第一次动画。
HTML:
<div id="wrapper">
<div id="uphour"></div>
<div id="upminute"></div>
<div id="upampm"></div>
<div class="animated">
<div id="hour" data-hour="1">2</div>
</div>
<div class="animated">
<div id="minute" data-minute="1">50</div>
</div>
<div class="animated">
<div id="ampm" data-minute="AM">AM</div>
</div>
<div id="downhour"></div>
<div id="downminute"></div>
<div id="downampm"></div>
</div>
(这里的数据属性目前没有使用)
SCSS:
$finger: 2cm;
$smallfinger: .3cm;
#wrapper {
display: grid;
grid-template-columns: $finger $finger $finger;
grid-template-rows: $finger $finger $finger;
grid-column-gap: $smallfinger;
grid-row-gap: $smallfinger;
position:absolute;
width: 100vw;
background: #FF00FF;
height: calc( (#{$finger} * 3) + (#{$smallfinger} * 4) );
box-sizing: border-box;
bottom:$finger;
left:0;
padding:0;
margin:0;
align-content: center;
justify-content: center;
}
#uphour,
#upminute,
#upampm,
#downhour,
#downminute,
#downampm {
display: flex;
background: rgba(255,0,0,.4);
width: $finger;
height: $finger;
margin-left: 1vw;
margin-right: 1vw;
border: 1px solid black;
}
.animated {
display: flex;
width: $finger;
height: $finger;
margin-left: 1vw;
margin-right: 1vw;
border: 1px solid black;
overflow:hidden;
}
#minute, #hour, #ampm {
display: flex;
/*background: rgba(255,0,0,.4); for testing of animation only*/
width: $finger;
height: $finger;
border: 0;
position: relative;
align-items: center;
justify-content: center;
font-size: .8cm;
}
.animateStart {
-webkit-animation-name: downandout; /* Safari 4.0 - 8.0 */
animation-name: downandout;
-webkit-animation-duration: 250ms; /* Safari 4.0 - 8.0 */
animation-duration: 250ms;
/*-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;*/
transition-timing-function: cubic-bezier(1,0,0,1);
}
/* Safari 4.0 - 8.0 */
@-webkit-keyframes downandout {
0% {top: 0; left: 0;}
10% {top: 100%; left:0;}
50% {top: 100%; left: 100%;}
90% {top: -100%; left:100%;}
}
/* Standard syntax */
@keyframes downandout {
0% {top: 0; left: 0;}
40% {top: 100%; left:0;}
42% {top: 100%; left: calc(#{$finger} * 2);}
48% {top: -110%; left: calc(#{$finger} * 2);}
50% {top: -110%; left:0;}
100% {top: 0; left:0;}
}
Javascript:
var uphourEl = document.getElementById("uphour");
var downhourEl = document.getElementById("downhour");
var upminuteEl = document.getElementById("upminute");
var downminuteEl = document.getElementById("downminute");
var upampmEl = document.getElementById("upampm");
var downampmEl = document.getElementById("downampm");
uphourEl.addEventListener("click", increaseHour);
downhourEl.addEventListener("click", decreaseHour);
upminuteEl.addEventListener("click", increaseMinute);
downminuteEl.addEventListener("click", decreaseMinute);
upampmEl.addEventListener("click", swapAMPM);
downampmEl.addEventListener("click", swapAMPM);
var hourEl = document.getElementById("hour");
var minuteEl = document.getElementById("minute");
var ampmEl = document.getElementById("ampm");
function increaseHour() {
let value = hourEl.innerHTML;
if (value > 11) {
value = 1
} else {
value++;
}
hourEl.innerHTML = value;
console.log(value);
}
function decreaseHour() {
let value = hourEl.innerHTML;
if (value < 2) {
value = 12
} else {
value--;
}
hourEl.innerHTML = value;
console.log(value);
}
function increaseMinute() {
let value = minuteEl.innerHTML;
if (value > 58) {
value = 0
} else {
value++;
}
minuteEl.innerHTML = value;
console.log(value);
}
function decreaseMinute() {
let value = minuteEl.innerHTML;
if (value < 1) {
value = 59
} else {
value--;
}
minuteEl.innerHTML = value;
console.log(value);
}
function swapAMPM() {
let value = ampmEl.innerHTML;
if (ampmEl.hasAttribute("class")) {
ampmEl.removeAttribute("class");
}
ampmEl.setAttribute("class", "animateStart");
if (value === "AM") {
value = "PM";
ampmEl.innerHTML = value;
console.log("Changed from AM");
} else {
value = "AM";
ampmEl.innerHTML = value;
console.log("Changed from PM");
}
}
..这是 swapAMPM 函数(在 Javascript 的末尾),我目前无法按预期运行。
关于我为什么会遇到这种行为的任何建议?我缺少一些最佳实践吗?
解决方案
我想这就是你在香草中会做的事情
gugateider 是对的,你需要一个 setTimout,有 AnimationEvent API,但它不完全支持。
以下是一种简化的方法:
不需要事件监听器或收集 ID
更新:
- 包括去抖动以停止多次单击同一按钮
- 调整超时(添加了超时,以便值在视野之外改变,从而产生数字实际旋转的错觉,AnimationEvent 无法检测到您是否已完成动画的一半。)
<div class="wrapper">
<div id="hour" class="unit">
<div class="plus button" onClick="pressedButton(event);">+</div>
<div class="value"><div>10</div></div>
<div class="minus button" onClick="pressedButton(event);">-</div>
</div>
<div id="minute" class="unit">
<div class="plus button" onClick="pressedButton(event);">+</div>
<div class="value"><div>36</div></div>
<div class="minus button" onClick="pressedButton(event);">-</div>
</div>
<div id="meridiem" class="unit">
<div class="plus button" onClick="pressedButton(event);">+</div>
<div class="value"><div>AM</div></div>
<div class="minus button" onClick="pressedButton(event);">-</div>
</div>
</div>
.wrapper {
display: flex;
flex-flow: row no-wrap;
justify-content: space-between;
align-items: center;
width: 200px;
height: 200px;
margin: 100px auto;
background: red;
padding: 20px;
}
.unit {
display: flex;
flex-flow: column;
justify-content: space-between;
align-items: space-between;
height: 100%;
position: relative;
}
.button {
border: 2px solid black;
height: 50px;
width: 50px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
background: grey;
&:hover {
opacity: 0.8;
}
}
.value {
border: 2px solid black;
height: 50px;
width: 50px;
font-family: sans-serif;
font-size: 20px;
display: flex;
justify-content: center;
align-items: center;
background: lightgrey;
overflow: hidden;
}
.animate {
top: 0;
position: relative;
overflow: hidden;
animation-name: downandout;
animation-duration: 1s;
animation-iteration-count: 1;
transition-timing-function: ease-in-out;
&--reverse {
animation-direction: reverse;
}
}
@keyframes downandout {
0% {top: 0}
50% {top: 50px}
51% {top: -50px}
100% {top: 0}
}
debounce = function(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
pressedButton = function($event) {
$event.preventDefault();
// debouncedFn to stop multiple clicks to the same button
var debouncedFn = debounce(function() {
// All the taxing stuff you do
const target = $event.target;
const elm = target.parentNode.children[1];
let direction;
// clone the element to restart the animation
const newone = elm.cloneNode(true);
// add the first animate
newone.children[0].classList.add("animate");
// What button was pressed
if (target.classList.contains("minus")) {
direction = "down";
} else {
direction = "up";
}
// direction of animation
if (direction === "down") {
newone.children[0].classList.add("animate--reverse");
} else {
newone.children[0].classList.remove("animate--reverse");
}
// add the new element to the DOM
elm.parentNode.replaceChild(newone, elm);
// change value after half of the animation has completed
setTimeout(function() {
switch (target.parentNode.id) {
case "hour":
case "minute":
if (direction === "down") {
newone.children[0].innerText--;
} else {
newone.children[0].innerText++;
}
break;
case "meridiem":
if (newone.children[0].innerText === "PM") {
newone.children[0].innerText = "AM";
} else {
newone.children[0].innerText = "PM";
}
}
}, 100);
}, 250);
// Call my function
debouncedFn();
};
推荐阅读
- r - 用不同类型的缺失替换一系列变量中的 NA
- ios - ObservableObject 正在更新所有视图并导致 SwiftUI 中的菜单关闭
- php - 为什么 DateTimeZone :: listAbbreviations() 和 DateTimeZone :: listIdentifiers () 之间存在不同的时区
- r - 根据条件使一些样本名称唯一
- c# - Cosmos DB 加快读取速度
- javascript - Uncaught UnknownError:无法在“MediaRecorder”上执行“start”:启动 MediaRecorder 时出错
- azure-devops - 从测试计划运行自动化测试给出错误未找到测试源
- sql - 使用项目值作为选择代码的一部分
- django - django-datatable-view==0.9.0 Django 3.1.3:ImportError:无法导入名称'FieldDoesNotExist'
- vue.js - 刷新后如何使vue导航守卫工作