2017-05-14 38 views
1

我最近一直在學習更多的JavaScript,因爲我將在即將到來的實習中使用它。該公司推薦的許多不同的資源給我看,但我的一個朋友也建議這個網站:錯誤與transitionend事件不正確刪除一個CSS類

https://javascript30.com/

我決定給它一個嘗試,第一個項目,該項目是一個JavaScript鼓組開始昨天。

所以整個項目並不難,但我注意到一個小錯誤正在發生。因此,該項目將一個'keydown'事件監聽器附加到幾個不同的HTML元素,這些元素在按下任何一個ASDFGHJKJL時都會觸發。除了播放聲音之外,監聽器還會爲該按鍵添加一點效果的元素。

要刪除類,我們將一個transitionend偵聽器附加到這些元素。因此,當CSS屬性在按下按鍵後完成轉換時,該類將被刪除,並且圖形將在瀏覽器中恢復正常。

現在,如果你慢慢地按下鍵,它可以很好地工作。但我注意到,如果您要將按鍵按下一兩秒,看起來好像添加的類永遠不會被移除,並且圖形是永久的。然後我檢查了控制檯並注意到一旦它被卡住,transitionend事件從不會觸發。

以下是完成文件的代碼。

function removeTransition(e) 
{ 
    if (e.propertyName !== 'transform') 
     return; 
    e.target.classList.remove('playing'); 
} 

function playSound(e) 
{ 
    const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`); 
    const key = document.querySelector(`div[data-key="${e.keyCode}"]`); 
    if (!audio) 
     return; 

    key.classList.add('playing'); 
    audio.currentTime = 0; 
    audio.play(); 
} 

這就是我們如何連接的transitionend監聽器,不知道這會有什麼關係呢

const keys = Array.from(document.querySelectorAll('.key')); 
keys.forEach(key => key.addEventListener('transitionend', removeTransition)); 

所以我們放在if循環中removeTransition功能,使得它不不要刪除每個正在轉換的屬性的類,但我注意到,當您刪除if循環時,該頁面完美地工作。

所以我不完全確定transitionend事件發生了什麼,爲什麼一旦它被卡住就會完全停止發射。而且,爲什麼它在if循環被刪除時工作。當它循環遍歷所有的屬性時,它可能有更多的機會去除這個類?沒有線索。想知道這裏有人可能知道發生了什麼事。

編輯:

我改變了playSound功能一點點嘗試,並得到這條底線。

function playSound(e) 
{ 
    const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`); 
    const key = document.querySelector(`.key[data-key="${e.keyCode}"]`); 
    if(!audio) 
    { 
     return; 
    } 
    if(key.classList.contains("playing")) 
    { 
     console.log("True"); 
     key.classList.remove("playing"); 
    } 
    audio.currentTime = 0; 
    audio.play(); 
    console.log("adding"); 
    key.classList.add("playing"); 
} 

所以我添加了一個if語句來檢查元素是否已經包含「正在播放」的類,一旦卡住了。我還添加了一個classList.remove調用,試圖擺脫它在同一分支。我發現它一旦卡住了,我再次按下該鍵,它分支到if語句並打印控制檯消息,但STILL不會刪除「正在播放」的類。

+0

另一種解決方案可以複製在MCVE您的問題?我已經採取了一些你的代碼,並把它放到一個小提琴,但它似乎工作正常。 – Terry

+0

https://codepen.io/anon/pen/PmazjN 你使用什麼瀏覽器?我正在使用Chrome。不知道這是否可能,但我想問問。 我通過HTML複製,其中包括JavaScript和CSS。我評論了所有的聲音,因爲你們沒有這些文件。不過,我仍然能夠複製它。 – Pilpod

回答

0

有2個原因此無法除去CSS類問題:

  1. 該標誌來標記動畫播放是否是playing類,它也是以接通/關斷的動畫的關鍵。這個設置使問題變得非常複雜。
  2. 標記/標記更改爲添加/刪除類playing。這是一項DOM操作,其花費的時間超過了必要的時間。

要解決此問題,最好將標記/標記信息存儲在內存中(作爲變量),並在未完成轉換時停止鍵盤事件偵聽器。

商店標誌/在可變標記信息:

var keysUnderTransition = { 
    "65": 0, 
    "83": 0, 
    "68": 0, 
    "70": 0, 
    "71": 0, 
    "72": 0, 
    "74": 0, 
    "75": 0, 
    "76": 0 
}; 

由於每個元件將有2個轉變在一個週期。 0表示元素未處於轉換狀態(沒有轉換左側),2表示它處於第一個轉換中(2個轉換完成)​​,而1表示它處於上一個轉換中(1個轉換完成)​​。

在功能playSound,檢查和標記標誌:

if (keysUnderTransition[e.keyCode]) { 
    return; 
} 
keysUnderTransition[e.keyCode] = 2; 

在功能removeTransition,還原標記/標記:

var dataKey = this.getAttribute('data-key'); 
    var underTransitionVal = keysUnderTransition[dataKey]; 
    if (underTransitionVal === 2) { 
    setTimeout(function() { 
     keysUnderTransition[dataKey] = 1; 
    }, 50); 
    } else if (underTransitionVal === 1) { 
    keysUnderTransition[dataKey] = 0; 
    } 

我使用50在上面的代碼來改變在第二次轉換結束之前的標誌。

這是一個工作jsfiddle

0

transitionend事件可以被中斷並且根本不會被觸發。如果用戶滾動或執行任何其他具有更高優先級的事件,就會發生這種情況。如果transitionend事件觸發,則需要包含回退並將其取消。

我在移動應用程序中觸摸滾動時遇到了類似的問題,我在此處爲動畫滑塊添加了動畫。

所以......

function transitionEndHandler(...){ 
    //remove the class 
    clearTimeout(fallback); 
} 

var fallback = setTimeout(function(){ 
    //remove the class 
}, timeOfTransition); 

如果該類沒有得到來自transitionend刪除,setTimeout函數會照顧它。

0

而且沒有超時

window.addEventListener('keyup', function (e) { 
    const key = document.querySelector(`.key[data-key="${e.keyCode}"]`) 
    if(key && key.classList.contains('playing')) key.classList.remove('playing'); 
});