我有下面的示例代码,它创建了从屏幕顶部飞出的祝酒词,停留几秒钟,然后飞走:
function createToast() {
const elem = document.createElement("div");
elem.classList.add("toast");
elem.innerText = "hello";
document.body.appendChild(elem);
setTimeout(() => elem.remove(), 3000);
}
setInterval(createToast, 3000);
body {
background-color: #d7d7d7;
}
.toast {
display: flex;
justify-content: center;
align-items: center;
padding: 5px 10px;
max-width: 200px;
transform: translate(0, 0);
background-color: #fff;
border-radius: 50px;
animation-name: toastin, toastout;
animation-duration: 0.3s, 0.5s;
animation-iteration-count: 1, 1;
animation-delay: 0s, 2.5s;
animation-fill-mode: forwards, forwards;
}
@keyframes toastin {
from {
opacity: 0;
transform: translate(0, -40px);
}
to {
opacity: 1;
transform: translate(0, 20px);
}
}
@keyframes toastout {
from {
opacity: 1;
transform: translate(0, 20px);
}
to {
opacity: 0;
transform: translate(50vw, 20px);
}
}
<body><body>
这工作得很好,但有时在我的应用程序中,会在当前toast消失之前创建另一个toast。在这种情况下,我希望当前toast在创建新toast时立即飞走,而不是等待2.5秒。
我怎么也想不明白这是怎么回事。这可能吗?这似乎很简单,但是我做的一切似乎都没有效果。
首先,我尝试抓住现有的toast元素并将animation-delay
设置为0s
,但没有效果。然后我尝试用一个全新的动画代替它,尝试使用!important
等。在所有情况下,吐司就像消失了一样,没有动画发生。
是否有任何方法可以让toast在创建新toast时立即在0.4秒内完成当前动画?这样它就能在撞上来的吐司之前飞走?
我对你的方法做了一些调整:
-
与其同时分配两个动画,不如只将
toastout
动画分配给某个类,比如.out
。 -
当试图移除敬酒时,调用
removeToast()
函数。它将类.out
添加到toast中。因此,您可以控制何时播放toastout
动画,然后在动画播放后,使用事件animationend
删除元素。 -
每次添加新的toast时,尝试在每个现有的toast上调用
removeToast()
。
完整的解决方案如下:
function createToast() {
// remove all existing toasts
[...document.querySelectorAll('.toast')].forEach(removeToast);
const elem = document.createElement("div");
elem.classList.add("toast");
elem.innerText = "hello";
setTimeout(() => removeToast(elem), 3000);
document.body.appendChild(elem);
}
function removeToast(toast) {
// if a toast is already removed, ignore
if (!toast || toast.classList.contains('out')) return;
toast.classList.add('out');
toast.addEventListener('animationend', () => toast.remove());
}
body {
background-color: #d7d7d7;
}
.toast {
display: flex;
position: fixed;
justify-content: center;
align-items: center;
padding: 5px 10px;
max-width: 200px;
transform: translate(0, 0);
background-color: #fff;
border-radius: 50px;
animation-name: toastin;
animation-duration: 0.3s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
.toast.out {
animation-name: toastout;
}
@keyframes toastin {
from {
opacity: 0;
transform: translate(0, -40px);
}
to {
opacity: 1;
transform: translate(0, 20px);
}
}
@keyframes toastout {
from {
opacity: 1;
transform: translate(0, 20px);
}
to {
opacity: 0;
transform: translate(50vw, 20px);
}
}
<body>
<button onclick="createToast()">Add toast</button>
<body>
你认为这是可能的,对吧?也许您需要添加一个变量来检查是否显示了toast。如果有一个toast正在显示,您可以立即应用em.remove()来只显示新的toast。看看下面是否适合你。
let isToastDisplayed = false;
function createToast() {
const elem = document.createElement("div");
elem.classList.add("toast");
elem.innerText = "hello";
document.body.appendChild(elem);
if (isToastDisplayed) {
const currentToast = document.querySelector(".toast");
currentToast.remove();
}
isToastDisplayed = true;
setTimeout(() => {
elem.remove();
isToastDisplayed = false;
}, 3000);
}
setInterval(createToast, 3000);
body {
background-color: #d7d7d7;
}
.toast {
display: flex;
justify-content: center;
align-items: center;
padding: 5px 10px;
max-width: 200px;
transform: translate(0, 0);
background-color: #fff;
border-radius: 50px;
animation-name: toastin, toastout;
animation-duration: 0.3s, 0.5s;
animation-iteration-count: 1, 1;
animation-delay: 0s, 2.5s;
animation-fill-mode: forwards, forwards;
}
@keyframes toastin {
from {
opacity: 0;
transform: translate(0, -40px);
}
to {
opacity: 1;
transform: translate(0, 20px);
}
}
@keyframes toastout {
from {
opacity: 1;
transform: translate(0, 20px);
}
to {
opacity: 0;
transform: translate(50vw, 20px);
}
}
<body><body>
不确定这是否直接回答了你的问题,但你可能能够在一个单独的类中分离动画…然后用js你可以检查现有的类并添加出来!
检查一下
function createToast() {
const existing = document.querySelectorAll('.toast')
if(existing.length > 0) {
existing.forEach(e => {
e.classList.add('toast-out')
})
}
const elem = document.createElement("div");
elem.classList.add("toast");
elem.innerText = "hello";
document.body.appendChild(elem);
setTimeout(() => elem.remove(), 3000);
}
setInterval(createToast, 2000);
body {
background-color: #d7d7d7;
}
.toast {
display: flex;
justify-content: center;
align-items: center;
padding: 5px 10px;
max-width: 200px;
transform: translate(0, 0);
background-color: #fff;
border-radius: 50px;
animation-name: toastin;
animation-duration: 0.3s;
animation-iteration-count: 1;
animation-delay: 0s;
animation-fill-mode: forwards;
}
.toast-out {
animation-name: toastout;
animation-duration: 0.5s;
animation-iteration-count: 1;
animation-delay: 0s;
animation-fill-mode: forwards;
}
@keyframes toastin {
from {
opacity: 0;
transform: translate(0, -40px);
}
to {
opacity: 1;
transform: translate(0, 20px);
}
}
@keyframes toastout {
from {
opacity: 1;
transform: translate(0, 20px);
}
to {
opacity: 0;
transform: translate(50vw, 20px);
}
}
<body><body>
您需要保留对elem的引用,并在再次调用该函数时将其删除。也许像这样:
let activeToast;
function clearToast() {
if(!activeToast){
return;
}
activeToast.remove();
activeToast = null;
}
function createToast() {
clearToast();
const elem = document.createElement("div");
elem.classList.add("toast");
elem.innerText = "hello";
activeToast = elem;
document.body.appendChild(elem);
setTimeout(() => clearToast(), 3000);
}
setInterval(createToast, 3000);
但是如果你想跟踪动画本身,你可能想使用一些动画事件。
https://medium.com/front-end-weekly/css-animation-events-in-javascript-d2bfe702636d