Animate.css promise 有时不会在 animationEnd 后清除 类
Animate.css promise sometimes doesn't clean the classes after animationEnd
我的页面中的标题很少,我使用与 Animate.css 不同的动画对每个标题进行动画处理。
首先,我将标题上的每个字母都包装在一个 span 元素中,然后我在 parent 上使用一个事件侦听器来查看它何时结束。
我使用 event.target 来确定哪个字母悬停在它上面,并使用 parent 节点来确定它的 class 是 parent 并给出相应的动画。
问题是有时有些字母没有动画。我看到这封信仍然有以前悬停的“animate__animated animate__(动画名称)”。
我使用来自 Animate.css 使用 promises 的网站的 JS 代码。
有谁知道为什么有时 classes 没有清理干净?我看到我正在尝试为很多元素制作动画,但我并没有将所有元素一起制作动画,最后我使用冒泡事件来 avit 我的事件列表器。
/// wrap every letter in a span
const words = document.querySelectorAll(".word");
words.forEach(function (e) {
e.innerHTML = e.textContent.replace(
/\bCristian\b|([^\x00-\x40]|\w|\S)/g,
(match, group) =>
group == undefined
? `<span class="cristian">${match}</span>`
: `<span class="letter">${match}</span>`
);
});
// anim letters function
const animationsSettings = [
["fede", "rubberBand"],
["myne", "bounce"],
["skills", "jello"],
["contact", "wobble"],
["tools", "swing"],
];
const animationPrefix = "animate__";
const defAnimationName = "jello";
let animationName = defAnimationName;
const regexClasses = () => {
let regex = ``;
for (settings of animationsSettings) {
regex += `\b${settings[0]}\b|`;
}
return regex.slice(0, -1);
};
const regexConst = new RegExp(regexClasses(), "");
function anim_letters(el, i) {
// check if el is an event or not
const node =
el.originalEvent instanceof Event || el.target ? el.target : el;
const parentClasses = node.parentNode.classList.value;
const parentClassMatch = parentClasses.match(regexConst);
if (
node.tagName == "SPAN" &&
node.className !== "word" &&
node.className !== "cristian"
) {
if (parentClassMatch) {
for (settings of animationsSettings) {
if (parentClassMatch[0] == settings[0]) {
animationName = settings[1];
break;
}
}
} else {
animationName = defAnimationName;
}
// We create a Promise and retu1rn it
new Promise((resolve, reject) => {
if (i) {
animationName = "jello";
node.style.animationDelay = `${i * 0.1 + 0.2}s`;
}
node.classList.add(
"animate__animated",
`${animationPrefix}${animationName}`
);
// When the animation ends, we clean the classes and resolve the Promise
function handleAnimationEnd(event) {
event.stopPropagation();
node.classList.remove(
"animate__animated",
`${animationPrefix}${animationName}`
);
node.style.animationDelay = "";
resolve("animation ended");
}
node.addEventListener("animationend", handleAnimationEnd, {
once: true,
});
});
}
}
const lettersStart = document.querySelectorAll(".lettersstart>.letter");
for (const [i, letter] of lettersStart.entries()) {
anim_letters(letter, i);
}
for (e of words) {
e.addEventListener("mouseover", anim_letters);
}
.letter{
display:inline-block
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" rel="stylesheet"/>
<h2 class="lettersstart word hi">Hi,</h2>
<h2 class="lettersstart im word">I'm
<span class="cristian">Cristian</span></h2>
<h3 class="myne word">Myne<wbr>social</h3>
<h3 class="fede word">Federico<wbr>Angeli</h3>
可以看到真实页面here
谢谢
我认为问题在于您的 animationName
变量是全局变量。当您为带有 class A 的字母制作动画时,然后在第一个动画完成之前将鼠标悬停在带有不同 class B 的字母上时,它将尝试从元素中删除 class B结束并卡在 class A 上。您应该可以通过简单地移动
来解决这个问题
let animationName = defAnimationName;
声明到 anim_letters
函数中。
/// wrap every letter in a span
const words = document.querySelectorAll(".word");
words.forEach(function (e) {
e.innerHTML = e.textContent.replace(
/\bCristian\b|([^\x00-\x40]|\w|\S)/g,
(match, group) =>
group == undefined
? `<span class="cristian">${match}</span>`
: `<span class="letter">${match}</span>`
);
// FIXME: XSS issue if textContent contains <>
});
// anim letters function
// use a simple lookup map instead of complicated and fragile regex stuff
const animationsSettings = new Map([
["fede", "rubberBand"],
["myne", "bounce"],
["skills", "jello"],
["contact", "wobble"],
["tools", "swing"],
]);
const animationPrefix = "animate__";
const defAnimationName = "jello";
function anim_letters(el, i) {
// check if el is an event or not
const node = el.originalEvent instanceof Event || el.target ? el.target : el;
if (node.tagName != "SPAN" || node.classList.contains("word") || node.classList.contains("cristian")) {
return Promise.resolve();
}
let animationName = defAnimationName
for (const className of node.parentNode.classList) {
if (animationsSettings.has(className)) {
animationName = animationsSettings.get(className);
break;
}
}
if (i) {
animationName = "jello";
node.style.animationDelay = `${i * 0.1 + 0.2}s`;
}
return new Promise((resolve, reject) => {
node.classList.add(
"animate__animated",
`${animationPrefix}${animationName}`
);
// When the animation ends, we clean the classes and resolve the Promise
function handleAnimationEnd(event) {
event.stopPropagation();
node.classList.remove(
"animate__animated",
`${animationPrefix}${animationName}`
);
node.style.animationDelay = "";
resolve("animation ended");
}
node.addEventListener("animationend", handleAnimationEnd, {
once: true,
});
});
}
const lettersStart = document.querySelectorAll(".lettersstart>.letter");
for (const [i, letter] of lettersStart.entries()) {
anim_letters(letter, i);
}
for (e of words) {
e.addEventListener("mouseover", anim_letters);
}
.letter {
display:inline-block
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" rel="stylesheet"/>
<h2 class="lettersstart word hi">Hi,</h2>
<h2 class="lettersstart im word">I'm
<span class="cristian">Cristian</span></h2>
<h3 class="myne word">Myne<wbr>social</h3>
<h3 class="fede word">Federico<wbr>Angeli</h3>
我的页面中的标题很少,我使用与 Animate.css 不同的动画对每个标题进行动画处理。 首先,我将标题上的每个字母都包装在一个 span 元素中,然后我在 parent 上使用一个事件侦听器来查看它何时结束。 我使用 event.target 来确定哪个字母悬停在它上面,并使用 parent 节点来确定它的 class 是 parent 并给出相应的动画。
问题是有时有些字母没有动画。我看到这封信仍然有以前悬停的“animate__animated animate__(动画名称)”。
我使用来自 Animate.css 使用 promises 的网站的 JS 代码。
有谁知道为什么有时 classes 没有清理干净?我看到我正在尝试为很多元素制作动画,但我并没有将所有元素一起制作动画,最后我使用冒泡事件来 avit 我的事件列表器。
/// wrap every letter in a span
const words = document.querySelectorAll(".word");
words.forEach(function (e) {
e.innerHTML = e.textContent.replace(
/\bCristian\b|([^\x00-\x40]|\w|\S)/g,
(match, group) =>
group == undefined
? `<span class="cristian">${match}</span>`
: `<span class="letter">${match}</span>`
);
});
// anim letters function
const animationsSettings = [
["fede", "rubberBand"],
["myne", "bounce"],
["skills", "jello"],
["contact", "wobble"],
["tools", "swing"],
];
const animationPrefix = "animate__";
const defAnimationName = "jello";
let animationName = defAnimationName;
const regexClasses = () => {
let regex = ``;
for (settings of animationsSettings) {
regex += `\b${settings[0]}\b|`;
}
return regex.slice(0, -1);
};
const regexConst = new RegExp(regexClasses(), "");
function anim_letters(el, i) {
// check if el is an event or not
const node =
el.originalEvent instanceof Event || el.target ? el.target : el;
const parentClasses = node.parentNode.classList.value;
const parentClassMatch = parentClasses.match(regexConst);
if (
node.tagName == "SPAN" &&
node.className !== "word" &&
node.className !== "cristian"
) {
if (parentClassMatch) {
for (settings of animationsSettings) {
if (parentClassMatch[0] == settings[0]) {
animationName = settings[1];
break;
}
}
} else {
animationName = defAnimationName;
}
// We create a Promise and retu1rn it
new Promise((resolve, reject) => {
if (i) {
animationName = "jello";
node.style.animationDelay = `${i * 0.1 + 0.2}s`;
}
node.classList.add(
"animate__animated",
`${animationPrefix}${animationName}`
);
// When the animation ends, we clean the classes and resolve the Promise
function handleAnimationEnd(event) {
event.stopPropagation();
node.classList.remove(
"animate__animated",
`${animationPrefix}${animationName}`
);
node.style.animationDelay = "";
resolve("animation ended");
}
node.addEventListener("animationend", handleAnimationEnd, {
once: true,
});
});
}
}
const lettersStart = document.querySelectorAll(".lettersstart>.letter");
for (const [i, letter] of lettersStart.entries()) {
anim_letters(letter, i);
}
for (e of words) {
e.addEventListener("mouseover", anim_letters);
}
.letter{
display:inline-block
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" rel="stylesheet"/>
<h2 class="lettersstart word hi">Hi,</h2>
<h2 class="lettersstart im word">I'm
<span class="cristian">Cristian</span></h2>
<h3 class="myne word">Myne<wbr>social</h3>
<h3 class="fede word">Federico<wbr>Angeli</h3>
可以看到真实页面here
谢谢
我认为问题在于您的 animationName
变量是全局变量。当您为带有 class A 的字母制作动画时,然后在第一个动画完成之前将鼠标悬停在带有不同 class B 的字母上时,它将尝试从元素中删除 class B结束并卡在 class A 上。您应该可以通过简单地移动
let animationName = defAnimationName;
声明到 anim_letters
函数中。
/// wrap every letter in a span
const words = document.querySelectorAll(".word");
words.forEach(function (e) {
e.innerHTML = e.textContent.replace(
/\bCristian\b|([^\x00-\x40]|\w|\S)/g,
(match, group) =>
group == undefined
? `<span class="cristian">${match}</span>`
: `<span class="letter">${match}</span>`
);
// FIXME: XSS issue if textContent contains <>
});
// anim letters function
// use a simple lookup map instead of complicated and fragile regex stuff
const animationsSettings = new Map([
["fede", "rubberBand"],
["myne", "bounce"],
["skills", "jello"],
["contact", "wobble"],
["tools", "swing"],
]);
const animationPrefix = "animate__";
const defAnimationName = "jello";
function anim_letters(el, i) {
// check if el is an event or not
const node = el.originalEvent instanceof Event || el.target ? el.target : el;
if (node.tagName != "SPAN" || node.classList.contains("word") || node.classList.contains("cristian")) {
return Promise.resolve();
}
let animationName = defAnimationName
for (const className of node.parentNode.classList) {
if (animationsSettings.has(className)) {
animationName = animationsSettings.get(className);
break;
}
}
if (i) {
animationName = "jello";
node.style.animationDelay = `${i * 0.1 + 0.2}s`;
}
return new Promise((resolve, reject) => {
node.classList.add(
"animate__animated",
`${animationPrefix}${animationName}`
);
// When the animation ends, we clean the classes and resolve the Promise
function handleAnimationEnd(event) {
event.stopPropagation();
node.classList.remove(
"animate__animated",
`${animationPrefix}${animationName}`
);
node.style.animationDelay = "";
resolve("animation ended");
}
node.addEventListener("animationend", handleAnimationEnd, {
once: true,
});
});
}
const lettersStart = document.querySelectorAll(".lettersstart>.letter");
for (const [i, letter] of lettersStart.entries()) {
anim_letters(letter, i);
}
for (e of words) {
e.addEventListener("mouseover", anim_letters);
}
.letter {
display:inline-block
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" rel="stylesheet"/>
<h2 class="lettersstart word hi">Hi,</h2>
<h2 class="lettersstart im word">I'm
<span class="cristian">Cristian</span></h2>
<h3 class="myne word">Myne<wbr>social</h3>
<h3 class="fede word">Federico<wbr>Angeli</h3>