2017-05-14 4 views
1

最近、私は今後のインターンシップに多大な貢献をしています。私が見する同社は、さまざまなリソースをお勧めしますが、私の友人にもこのサイトを示唆した:CSSクラスを正常に削除していないバグENDYENDイベント

https://javascript30.com/

私はそれを試してみることにしましたし、JavaScriptのドラムキットだった最初のプロジェクトで昨日始めました。

全体的なプロジェクトは難しくありませんでしたが、起こっていた小さなバグに気付きました。そのため、このプロジェクトでは、いずれかのASDFGHJKJLが押されたときに起動するいくつかの異なるHTML要素に「keydown」イベントリスナーを関連付けます。リスナーは、サウンドを再生するだけでなく、押されているキーに少しの効果を加えるクラスを要素に付け加えます。

クラスを削除するには、要素にトランジェントリスナーを追加しました。したがって、キーを押した後にCSSプロパティがトランジションを終了すると、クラスは削除され、ブラウザのグラフィックスは通常の状態に戻ります。

これで、キーをゆっくりと押すと、完全に正常に動作します。しかし、私が気づいたのは、1〜2秒間キーを押し続けると、追加されるクラスが決して削除されず、グラフィックが永久的であるように見えるということです。私はその後、コンソールをチェックし、移行イベントが一度それのように立ち往生したら、決して起動しないことに気づいた。

ここに完成したファイルのコードを示します。

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(); 
} 

そして、これは、それはdoesnのように、だから我々はremoveTransition機能であればループに入れて、我々はtransitionendリスナーを添付する方法、これはそれで

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

を行うには何を持っているかどうかわからないです移行している各プロパティのクラスを削除しないでくださいが、ifループを削除するとページが完全に機能することに気付きました。

私はtransitionendイベントで何が起こっているのか、なぜそれがちょうどそのようになったら完全に終了するのをなぜ止めているのか完全にはわかりません。また、ifループが削除されたときに、なぜ動作するのでしょうか。おそらく、クラスがすべてのプロパティをループするときにクラスを削除する可能性がさらに高いでしょうか?全く分からない。誰がここで何が起こっているのか知っているのだろうかと疑問に思いました。

EDIT:

私が試してみて、これの一番下に到達するために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文に分岐してコンソールメッセージを表示しますが、「再生」クラスは削除されません。

+0

せずに別の解決策あなたはMCVEであなたの問題を再現することはできますか?私はあなたのコードのいくつかを取って、それをフィドルに入れましたが、それは正常に動作しているようです。 – Terry

+0

https://codepen.io/anon/pen/PmazjN どのブラウザをお使いですか?私はChromeを使用しています。それが可能かどうかは分かりませんが、私は聞きたいと思っていました。 javascriptとCSSを含むHTMLをコピーしました。私はあなたのためにファイルを持っていないので、すべての音質をコメントアウトしました。私はまだそれを複製することができました。 – Pilpod

答えて

0

CSSクラス問題削除することができませんでしこののための2つの原因があります。

  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 
}; 

は、1サイクルで2つの遷移を有することになります。 0は、要素が遷移していない(遷移が残っていない)ことを意味し、2は最初の遷移(2つの遷移が完了するまで残っていること)を意味し、1は最後の遷移私は変更する上記のコードで50を使用

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; 
    } 

:機能removeTransition

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

、復帰フラグ/マーク:機能playSound

、チェックフラグをマーク第2の遷移の終了前にフラグを立てる。

ここには、作業jsfiddleがあります。

0

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'); 
}); 
関連する問題