2013-12-10 12 views
17

Nella mia funzione close voglio eseguire tutte le operazioni di ripulitura del DOM dopo che le transizioni di css hanno terminato l'esecuzione. Ma potrebbero non esserci transizioni in esecuzione/potrebbero essere multi-stage - (il mantenimento dei fogli di stile è fuori dalle mie mani).È possibile rilevare se è iniziata una transizione CSS arbitraria

Come potrei fare per scrivere una funzione simile al seguente

function close() { 
    myEl.removeClass('open'); 
    if (animation is running/about to be run) { 
    // wait for transition to end, then recursively check to see if another 
    // one has started, wait for that ... 
    // then 
    cleanUpDOM(); 
    } else { 
    cleanUpDOM(); 
    } 
} 

I miei pensieri finora sono per avvolgere il controllo iniziale in un timeout/requestAnimationFrame al fine di dare l'animazione la possibilità di iniziare poi la verifica per vedere se è in esecuzione. Sfortunatamente, senza un evento transitionstart non ho idea di come controllare se una transizione è iniziata.

modificare risposte raccomandano jquery sono irrilevanti come le animazioni jQuery sono le animazioni JavaScript, non transizioni CSS

+0

se sai cosa proprietà viene animato è possibile determinare se l'animazione è in corso confrontando il valore della proprietà corrente elementi con quello che è il valore di stile CSS (aka target) è? – milks

+0

@milks In generale non saprò cosa si sta passando, o anche se qualcosa è in fase di transizione. (Lo scenario peggiore è in effetti più complesso - potrei anche non sapere se la transizione è sull'elemento esterno, ad es. Nella sovrapposizione l'area del contenuto interno potrebbe ridursi a un punto sebbene la sovrapposizione esterna rimanga nera ... ma questo scenario non è 't così importante per ora) – wheresrhys

+0

Penso che questo è un duplicato di http://stackoverflow.com/questions/2087510/callback-on-css-transition –

risposta

1

A proposito di eventi transitionStart e transitionEnd:

La transizione non può parte da nessuna parte. Di solito la transizione inizia dopo un certo evento, in cui si modifica lo stato dell'elemento DOM cambiando gli stili per classe o qualcos'altro. Quindi, sai quando inizia la transizione perché lo si avvia nel codice.

Durante la transizione, l'I/O utente non blocca, quindi la transizione è asincrona e quindi la transizione termina quando non si conosce bene. Quindi hai bisogno dell'evento transitionEnd per fare qualcosa, quindi la transizione è finita in javascript.

Circa evento transitionEnd: Basta guardare la jsfiddle

+4

Non lo avvio esplicitamente nel mio codice 'js'. Aggiungo una classe in 'js', che applica alcuni stili nel' css' che * may * implica una transizione, quindi my 'js' non sa se sta iniziando una transizione – wheresrhys

+0

È possibile controllare il supporto di transizione (con prefissi o meno) di [Modernizr] (http://modernizr.com/). Se la transizione è supportata puoi controllare gli oggetti di stile per 'transitionDelay',' transitionDuration' e 'transitionProperty' e ottenere valori per sapere che la transizione inizierà o meno. – Pinal

+0

Non si può sapere con certezza quando la transizione inizia perché si tratta di un'operazione asincrona eseguita dai browser che non si sa quando. Date un'occhiata: https://stackoverflow.com/questions/27275872/race-condition-with-css-transitions-and-transitionend-event-cannot-find-a-solu – demian85

1

Ecco la mia soluzione finora - un po 'hacky e funziona solo quando il quale elemento potrebbe transizione è noto, e non funziona con transition-property: all ... ma si tratta di un inizio promettente

function toCamelStyleProp (str) { 
    return str.replace(/(?:\-)([a-z])/gi, function ($0, $1) { 
     return $1.toUpperCase(); 
    }); 
} 

function toHyphenatedStyleProp (str) { 
    return str.replace(/([A-Z])/g, function (str,m1) { 
     return '-' + m1.toLowerCase(); 
    }).replace(/^ms-/,'-ms-'); 
} 

function getPrefixedStyleProp (prop) { 
    prop = toCamelStyleProp(prop); 
    prop = Modernizr.prefixed(prop); 
    return toHyphenatedStyleProp(prop); 
} 

function getStyleProperty (el, prop) { 
    return getComputedStyle(el,null).getPropertyValue(getPrefixedStyleProp(prop)); 
} 

function doAfterTransition ($wrapper, cssClass, mode, $transitioningEl, callback) { 
    $transitioningEl = $transitioningEl || $wrapper; 

    var transitioningEl = $transitioningEl[0], 
     duration = +getStyleProperty(transitioningEl, 'transition-duration').replace(/[^\.\d]/g, ''), 
     transitioners = getStyleProperty(transitioningEl, 'transition-property').split(' '), 
     initialState = [], 
     changedState = [], 
     i, 
     callbackHasRun = false, 

     //makes sure callback doesn't get called twice by accident 
     singletonCallback = function() { 
      if (!callbackHasRun) { 
       callbackHasRun = true; 
       callback(); 
      } 
     }; 

    // if no transition defined just call the callback 
    if (duration === 0) { 
     $wrapper[mode + 'Class'](cssClass); 
     callback(); 
     return; 
    } 

    for (i = transitioners.length - 1;i>=0;i--) { 
     initialState.unshift(getStyleProperty(transitioningEl, transitioners[i])); 
    } 

    $wrapper[mode + 'Class'](cssClass); 

    setTimeout(function() { 
     for (i = transitioners.length - 1;i>=0;i--) { 
      changedState.unshift(getStyleProperty(transitioningEl, transitioners[i])); 
     } 

     for (i = transitioners.length - 1;i>=0;i--) { 
      if (changedState[i] !== initialState[i]) { 
       $transitioningEl.transitionEnd(singletonCallback); 

       // failsafe in case the transitionEnd event doesn't fire 
       setTimeout(singletonCallback, duration * 1000); 
       return; 
      } 
     } 
     singletonCallback(); 
    }, 20); 
} 
-1

Se hai intenzione di fare la transizione css, è possibile controllare jQuery Plugin Transit http://ricostacruz.com/jquery.transit/

Molto potente e utile, è possibile ottenere il valore x di trasformazione con. css ('x') per esempio.

-1

Su animation.css ho trovato questo.

Si può anche rilevare quando un'animazione si conclude:

$('#yourElement').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', doSomething); 

read full doc here

1

Non c'è modo (che io sappia) per rilevare se una transizione sta attualmente lavorando in background senza conoscere l'elemento che è in fase di transizione.

Tuttavia, se è possibile spostarsi dalla transizione alle animazioni dei fotogrammi chiave, allora si avrà l'evento necessario - animationStart e animationEnd e quindi sarà facile capire se ci sono animazioni in esecuzione.

1

Hai provato lo pseudo JQuery ": animato"?

if ($ (elem) .è (': animato')) {...}

Guarda altrehttp://api.jquery.com/animated-selector/

+1

Questo funzionerà solo con l'animazione javascript di jquery https: //github.com/jquery/jquery/blob/master/src/effects/animatedSelector.js - guarda come si aspetta che ci sia un timer in jquery – wheresrhys

-1

si potrebbe utilizzare jQuery che sarebbe molto più facile, per esempio si potrebbe usare .animate come questo

(function(){ 
      var box = $('div.box') 
      $('button').on('click', function(){ 
       box.animate({ 'font-size' : '40px'}) 
       .animate({'color': 'red'}); 
      }) 
     })(); 

o semplicemente fare una funzione di callback

0

Ecco una funzione che attende che la pagina HTML diventi stabile. vale a dire quando tutte le animazioni sono finite. Nell'esempio seguente attende che l'Html rimanga invariato per 200 millisecondi e un timeout massimo di 2 secondi.

chiamare la funzione con ...

waitUntilHtmlStable(yourCallback, 200, 2000); 

La funzione ...

waitUntilHtmlStable = function (callback, unchangedDuration, timeout, unchangedElapsed, html) { 
    var sleep = 50; 
    window.setTimeout(function() { 
     var newHtml = document.documentElement.innerHTML; 
     if (html != newHtml) unchangedElapsed = 0; 
     if (unchangedElapsed < unchangedDuration && timeout > 0) 
      waitUntilHtmlStable(callback, unchangedDuration, timeout - interval, unchangedElapsed + interval, newHtml); 
     else 
      callback(); 
    }, sleep); 
}; 

Nel mio caso ho voluto essere sicuro che nuovi elementi ove presenti. Se si desidera tenere traccia il movimento di animazione quindi modificare il document.documentElement.innerHTML a

JSON.stringify(Array.prototype.slice.call(document.documentElement.getElementsByTagName("*"), 0) 
.map(function(e) { 
     var x = e; 
     var r = x.getBoundingClientRect(); 
     while (r.width == 0 || r.height == 0) { 
      x = x.parentNode; 
      r = x.getBoundingClientRect(); 
     } 
     return r; 
    })); 
Problemi correlati