3 回答
TA贡献1886条经验 获得超2个赞
我想这就是你在香草中的做法
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();
};
https://codepen.io/eddy14u/pen/VwZJmdW
TA贡献1828条经验 获得超4个赞
您可以使用动画迭代事件侦听器来检测动画何时结束,并正确删除您的类。为此,动画迭代必须设置为无限。在我的更改中,我还利用classList元素的属性从元素中添加/删除类。
注意:如果没有至少 1 次迭代,动画迭代事件将永远不会触发,因此代码将无法运行!
编辑:浏览器支持classList是最近的,所以如果你需要支持旧浏览器,你可以回退到不同的解决方案,或者添加一个classList polyfill
首先,我们需要一个函数来检测浏览器支持哪个动画迭代事件:
function whichAnimationEvent(){
var el = document.createElement("fakeelement");
var animations = {
"animation" : "animationiteration",
"OAnimation" : "oAnimationIteration",
"MozAnimation" : "animationiteration",
"WebkitAnimation": "webkitAnimationIteration"
};
for (let t in animations){
if (el.style[t] !== undefined){
return animations[t];
}
}
}
接下来,我们需要为该事件添加一个事件侦听器,当迭代触发时,我们从元素的 中删除该类classList,如下所示:
ampmEl.addEventListener(whichAnimationEvent(),function(){
console.log('ampmEl event listener fired')
ampmEl.classList.remove('animateStart');
});
接下来,我们将swapAMPM函数更改为在执行交换之前使用add元素的方法classList添加类,使其具有动画效果。
function swapAMPM() {
let value = ampmEl.innerHTML;
ampmEl.classList.add('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");
}
}
最后,我们需要更新 css 以进行infinite动画迭代,以便触发我们的事件。
.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);
}
TA贡献1951条经验 获得超3个赞
我知道 setTimeout 不是在那里使用的最佳选择,但是由于您已经完成了很多工作,您可以尝试用以下代码替换 swapAMPM 函数:
function swapAMPM() {
let value = ampmEl.innerHTML;
if (ampmEl.hasAttribute("class")) {
ampmEl.removeAttribute("class");
}
setTimeout( () => {
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");
}
}, 150);
}
添加回答
举报