2016-11-10 63 views
4

transitionEndトランジションでイベントが発生し、終了するトランジションは最初ので終了しますが、これは目的の動作ではありません。回避策はありますか?複数のトランジションを含むtransitionEndイベント、最後のトランジションを検出

document.querySelector('a').addEventListener('transitionend', function(){ 
 
    var time = (new Date().getMinutes()) + ':' + (new Date().getSeconds()); 
 
    console.log('transitionEnd - ', time); 
 
});
a{ 
 
    display:block; 
 
    opacity:.5; 
 
    width:100px; 
 
    height:50px; 
 
    background:lightblue; 
 
} 
 
a:hover{ 
 
    width:200px; 
 
    height:100px; 
 
    background:red; 
 
    transition: 4s width,  /* <-- "transitionEnd" should fire after this */ 
 
       2s height, 
 
       .5s background; 
 
}
<a>Hover me</a>

今、私は(私はそのブラウザを使用していない)Chromeで確認することを、私はイベントが3回、トランジションごとに1つずつ呼び出されることがわかります。とにかく、私は最後のものとFirefoxのために起動する必要があります。 (どのくらい多くのトランジションが最後にあったかを知るために、要素にどのくらいの数のトランジションがあるかわかりません)

+0

私は、バグ追跡されている - https://bugzilla.mozilla.org/show_bug.cgiを? id = 652543 – vsync

答えて

1

どのcssプロパティの合計が最長であるかを調べることがあります。これを行うには、<a>要素のwindow.getComputedStyleを使用し、すべてdurationdelayのプロパティを追加します。

通常のイベントハンドラでこれを行うことができます(これはかなり簡単です)。または、探しているプロパティ名を事前に計算する関数を作成します。このアプローチの

主な問題:

  • CSSはあなたには、いくつかのより多くのコンピューティングを行うために必要があるかもしれません、あなたは1つのステートメントでmssを使用することができます。
  • ホバー上でtransitionのスタイルを変更するときや、トランジションの直前/直後に新しいクラスを追加するときに、計算されたスタイルが何であるかを予測することは難しいことがあります。

var getValues = function(str) { 
 
    return str 
 
    .replace(/[A-Z]/gi, "") 
 
    .split(", ") 
 
    .map(parseFloat); 
 
}; 
 

 
var getMaxTransitionProp = function(el) { 
 
    var style = window.getComputedStyle(el); 
 
    var props = style.transitionProperty.split(", "); 
 

 
    var delays = getValues(style.transitionDelay); 
 
    var durations = getValues(style.transitionDuration); 
 
    var totals = durations.map(function(v, i) { 
 
    return v + delays[i]; 
 
    }); 
 

 
    var maxIndex = totals.reduce(function(res, cur, i) { 
 
    if (res.val > cur) { 
 
     res.val = cur; 
 
     res.i = i; 
 
    } 
 
    return res; 
 
    }, { 
 
    val: -Infinity, 
 
    i: 0 
 
    }).i; 
 

 
    return props[maxIndex]; 
 
} 
 

 
var lastEventListenerFor = function(el, cb) { 
 
    var lastProp = getMaxTransitionProp(el); 
 
    return function(e) { 
 
    if (e.propertyName == lastProp) { 
 
     cb(e); 
 
    } 
 
    }; 
 
} 
 

 
var a = document.querySelector("a"); 
 
var cb = function(e) { 
 
    console.log("End"); 
 
}; 
 

 
a.addEventListener("transitionend", lastEventListenerFor(a, cb));
a { 
 
    display: block; 
 
    opacity: .5; 
 
    width: 100px; 
 
    height: 50px; 
 
    background: lightblue; 
 
    transition: 3s width, 
 
    /* <-- "transitionEnd" should fire after this */ 
 
    2s height, .5s background; 
 
} 
 
a:hover { 
 
    width: 200px; 
 
    height: 100px; 
 
    background: red; 
 
}
<a>Hover me</a>

+0

あなたは洞窟から逃れるアイアンマンのスーツを作りました。 – vsync

0

私は今、それは多分、古い質問ですが、同じトラブルが発生しました。 はその方法で解決:

document.querySelector('a').addEventListener('click', function(e){ 
    this.classList.toggle('animate'); 
    let style = window.getComputedStyle(this, null); 
    Promise.all(style.transition.split(',').map((prop) => { 
    prop = prop.trim().split(/\s+/); 
    return Promise.race([ 
     new Promise((resolve) => { 
       let h = (e) => { 
        if (e.propertyName == prop[0]) 
         resolve('transitionEnd ' + prop[0]); 
       }; 
       this.addEventListener('transitionend', h, false); 
     }), 
     new Promise((resolve) => 
       setTimeout(
       () => resolve('TIMEOUT ' + prop[0]), 
        prop[1].replace(/s/,'')*1000 + 100 
      ) 
     ) 
    ]) 
    })) 
    .then((res) => { 
    console.log(res + 'DONE!!!!'); 
    /* do your stuff */ 
    }); 
}); 

説明:

  • まず我々は性質が実際にその後、 スプリット/マップ/操作を実行するために、それを変換し、変更すべきかを決定します。通常は次のような形式があります。「幅4sやすり0s、高さ2sやすり0s、..」
  • 次にPromiseを使用します。レースは必ずしもトランジションではないので、先にトリガされます(プロップは両方の状態で同じか、ルールとイベントでプロップ名が一致しません(背景は背景色かもしれません)、その他)単純なタイムアウトになるようにtpフォールバックが必要です
  • 最後に、我々は免責事項すべての各プロパティのタイムアウト/イベントリスナ

待つ:それは私はそれが魔法を大量に使用を認める例だし、チェック

  • 「コールバックの逃した多く

    • "も解雇される場合のアニメーションがキャンセルされた場合(タイムアウトはとにかく起動します)
    • ES6が必要です:)

    あなたはjsfiddle

  • 0

    transitionEndにそれで遊ぶことができ、イベントオブジェクトにpropertyNameというプロパティを返します。 Source

    そのため、あなたがしたいプロパティをテストし、コールバックをフィルタリングするために、単純なロジックを使用することができます。

    document.querySelector('a').addEventListener('transitionend', function(event){ 
        if(event.propertyName !== 'width') return; 
        console.log('transitionEnd - width!'); 
    }); 
    
    関連する問題