我正在嘗試為接收相同影片類的多個頁面元素同步 CSS 影片。
似乎有很多關于這個主題的帖子,但沒有統一的解決方案,而且我找到的解決方案似乎都不適用于這種情況。
我在這里準備了一個 jsfiddle 來演示這個問題:
https://jsfiddle.net/gdf7szo5/1/
如果您單擊任何字母,它將啟動該字母的影片。如果您再次單擊它會切換到不同的影片,如果您第三次單擊它會將字母設定為完全沒有影片。
所需的效果是讓一個影片中所有閃爍的字母彼此同步,而另一個影片中的所有字母彼此同步。需要明確的是,我并不是要同步這兩個影片——我只是希望具有給定影片的所有元素彼此同步。
但是目前,如果一個字母顯示影片,而您將另一個字母設定為同一個影片,除非您有絕對完美的計時,否則這兩個字母的影片將不同步,即使它們是相同的影片。
這是正在運行的代碼:
HTML:
<div>
<span id="spA" onclick="toggleFx('spA')">A</span>
<span id="spB" onclick="toggleFx('spB')">B</span>
<span id="spC" onclick="toggleFx('spC')">C</span>
<span id="spD" onclick="toggleFx('spD')">D</span>
</div>
CSS:
div {
display: flex;
flex-flow: column;
}
span {
animation-name: pulse_active;
}
span.pulse {
color: #f00;
animation: pulse_active 1.5s ease-in infinite;
}
span.pulse_invert {
color: #00f;
animation: pulse_inverted 3s ease-in infinite;
}
@keyframes pulse_active {
0% {
opacity: 0;
}
50% {
opacity: 0.66;
}
100% {
opacity: 0;
}
}
@keyframes pulse_inverted {
0% {
opacity: 1;
}
50% {
opacity: 0.33;
}
100% {
opacity: 1;
}
}
JS:
let pulseNormal = {};
let pulseInvert = {};
function toggleFx(spanID) {
let spanTarget = document.getElementById(spanID);
// shift setting
if (spanID in pulseInvert) {
console.log('y');
console.log(Object.keys(pulseInvert));
delete pulseInvert[spanID]
console.log(Object.keys(pulseInvert));
} else if (spanID in pulseNormal) {
pulseInvert[spanID] = true;
delete pulseNormal[spanID];
} else {
pulseNormal[spanID] = true
}
// update display
for (let sp of 'ABCD') {
let span = document.getElementById(`sp${sp}`);
// clear any prev animation
span.classList.remove('pulse');
span.classList.remove('pulse_invert');
// add/re-add animation as needed
if (`sp${sp}` in pulseNormal) {
span.classList.add('pulse');
} else if (`sp${sp}` in pulseInvert) {
span.classList.add('pulse_invert');
}
}
}
uj5u.com熱心網友回復:
為了同步它們,影片應該同時初始化。
在這里我指定了animation-namefor span,在定義其他道具之前影片不會運行(實際上我很想知道不同的渲染引擎是否共享相同的行為)。
let pulseList = {};
function toggleFx(spanID) {
let spanTarget = document.getElementById(spanID);
// toggle setting
if (spanID in pulseList) {
delete pulseList(spanID)
} else {
pulseList[spanID] = true;
}
// update display
for (let sp of 'ABCD') {
let span = document.getElementById(`sp${sp}`);
span.classList.remove('pulse'); // clear any prev animation
if (`sp${sp}` in pulseList) { // add/re-add animation as needed
span.classList.add('pulse');
}
}
}
div {
display: flex;
flex-flow: column;
}
span {
animation-name: pulse_active;
}
span.pulse {
color: #f00;
animation: pulse_active 1.5s ease-in infinite;
}
@keyframes pulse_active {
0% {
opacity: 0
}
50% {
opacity: 0.66
}
100% {
opacity: 0
}
}
<div>
<span id="spA" onclick="toggleFx('spA')">A</span>
<span id="spB" onclick="toggleFx('spB')">B</span>
<span id="spC" onclick="toggleFx('spC')">C</span>
<span id="spD" onclick="toggleFx('spD')">D</span>
</div>
編輯
至少 Blink 和 Gecko 確實具有相同的行為,我沒有在 WebKit Safari 上進行測驗。
uj5u.com熱心網友回復:
為此目的document.getAnimations()是一種有用的方法。它回傳當前有效的所有影片物件的陣列,其目標元素是檔案的后代。更多資訊:https : //developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations
document.getAnimations()包含currentTime屬性的專案,可用于同步影片。更多資訊:https : //drafts.c??sswg.org/web-animations/#dom-documentorshadowroot-getanimations
toggleFx 功能被修改,現在它分為三個部分。
在第一部分中,搜索document.getAnimations()并找到currentTime屬性 whereanimationName是pulse_activeor 之一pulse_inverted;然后將它們存盤在相關變數中(即pulseActiveStart和pulseInvertedStart)。
在第二部分,如你所說className的spanTarget改變了。
在第三部分,pulseActiveStart以及pulseInvertedStart施加到currentTime相關的影片(反向第一部分)的屬性。
function toggleFx(spanID) {
let spanTarget = document.getElementById(spanID);
let pulseActiveStart;
let pulseInvertedStart;
let anims = document.getAnimations()
for(let i = 0; i < anims.length; i ) {
if(anims[i].animationName == "pulse_active") pulseActiveStart = anims[i].currentTime;
else if(anims[i].animationName == "pulse_inverted") pulseInvertedStart = anims[i].currentTime;
}
if(spanTarget.classList.contains('pulse_invert')) {
spanTarget.classList.remove('pulse_invert');
spanTarget.classList.remove('pulse');
} else if(spanTarget.classList.contains('pulse')) {
spanTarget.classList.add('pulse_invert');
spanTarget.classList.remove('pulse');
} else {
spanTarget.classList.add('pulse');
}
anims = document.getAnimations()
for(let i = 0; i < anims.length; i ) {
if(anims[i].animationName == "pulse_active") {
if(pulseActiveStart) anims[i].currentTime = pulseActiveStart;
} else if(anims[i].animationName == "pulse_inverted") {
if(pulseInvertedStart) anims[i].currentTime = pulseInvertedStart;
}
}
}
div {
display: flex;
flex-flow: column;
}
span.pulse {
color: #f00;
animation: pulse_active 1.5s ease-in infinite;
}
span.pulse_invert {
color: #00f;
animation: pulse_inverted 3s ease-in infinite;
}
@keyframes pulse_active {
0% { opacity: 0; }
50% { opacity: 0.66; }
100% { opacity: 0; }
}
@keyframes pulse_inverted {
0% { opacity: 1; }
50% { opacity: 0.33; }
100% { opacity: 1; }
}
<div>
<span id="spA" onclick="toggleFx('spA')">A</span>
<span id="spB" onclick="toggleFx('spB')">B</span>
<span id="spC" onclick="toggleFx('spC')">C</span>
<span id="spD" onclick="toggleFx('spD')">D</span>
</div>
uj5u.com熱心網友回復:
我認為同步 CSS 影片是一個相當廣泛的話題,不能用一個包羅萬象的解決方案輕松解決。
在這種特定情況下,最直接的方法可能是跟蹤自pulse第一次添加類以來的時間,然后延遲所有后續pulse類添加以等待下一次影片迭代的開始。
請參閱修改后的 jsfiddle和建議的解決方案。它還稍微調整了樣式,以在等待下一次迭代時實作更平滑的過渡。希望它接近您想要實作的目標。
理論上,您可以使用基本時間偏移來“計算”并在pulse添加類之前更精確地設定第一輪影片延遲,以實作更平滑的過渡。但它也需要更多的數學運算,并且肯定會在某種程度上使代碼混亂。取決于你的目標和偏好。
如果有人知道一個更簡潔的解決方案,也許使用純 CSS 方法(?),那就太好了。
uj5u.com熱心網友回復:
基于@Amirreza Noori 的回答中的資訊,我設法用一個簡潔的小單線完成了這項作業:
for (let a of document.getAnimations()) { a.startTime = 0 }
無需查找現有影片的位置或區分特定影片——這只是重新啟動頁面上的所有影片。
如果將來我引入當頁面的其余影片重置時無法中斷的影片,那么該答案(以及其他資訊)中的其他資訊將很有幫助。但是,如果我可以避免這樣做,那么這種單襯似乎可以很好地切開芥末。
感謝大家的回答和見解!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/401873.html
標籤:javascript css
上一篇:Flexbox不換行文本
