2013-08-01 37 views
10

是否有可能使用javascript,jQuery或其他方法獲取/設置動畫CSS3的當前動畫百分比@keyframes獲取/設置當前@keyframes百分比/更改關鍵幀

舉例來說,有一個div,其類名爲.spin,它簡單地使用也稱爲spin的關鍵幀繞圈旋轉。

  1. 我曾嘗試使用$('.spin').css('animation')$('.spin').css('animation: spin')獲得動畫的當前百分比值,以及其他一些方法,但他們都警覺空

  2. 我也有興趣在改變原始動畫在每個預定義的關鍵幀%,我已嘗試像$('.spin').css('animation', '..new definition here...')$('.spin').css('spin', '50%', '...new definition here...)這樣的事情無濟於事。

任何想法?

回答

12

我大致實現了使用純CSS的CSS3。

對於我的實驗來想出一個方法來做到這些目標,我創建了一個基本的CSS3動畫,圍繞一個小的圓形路徑旋轉一個圓。我的目標是,在點擊一個按鈕時,動畫的起源更改爲新的位置

使用以下setInterval實現讓動畫的百分比值的第一個目標我只是近似當前百分比,它顯示近似的當前百分比。這將運行每隔40毫秒與動畫(milliseconds/100)

var result = document.getElementById('result'), currentPercent = 0; 
var showPercent = window.setInterval(function() { 
    if(currentPercent < 100) 
    { 
    currentPercent += 1; 
    } 
    else { 
    currentPercent = 0; 
    } 
    result.innerHTML = currentPercent; 
}, 40); 

注意這個解決方案的持續時間對應:

  • 它不是完美的,由於因爲計數器會被點擊另一個選項卡時運行,但動畫停止,因此它們變得不同步
  • 在最後一次點擊之後很長時間單擊該按鈕時也會出現錯誤。顯然,setInterval的運行有點比動畫長,所以他們越來越少了同步每個迭代
  • 我到處尋找更完美的解決方案,但一直未能拿出一個作爲尚未

要實現爲動畫的%值設置新定義的第二個目標,需要一些更復雜的解決方案。通過許多文章和網頁(以下重要的上市)澆築後,我設法想出了以下解決方案:

var circle = document.getElementById('circle'), 
    button = document.getElementById('button'); 
var result = document.getElementById('result'), 
    totalCurrentPercent = 0, 
    currentPercent = 0; 
var showPercent = window.setInterval(function() { 
    if(currentPercent < 100) 
    { 
    currentPercent += 1; 
    } 
    else { 
    currentPercent = 0; 
    } 
    result.innerHTML = currentPercent; 
}, 40); 
function findKeyframesRule(rule) { 
    var ss = document.styleSheets; 
    for (var i = 0; i < ss.length; ++i) { 
     for (var j = 0; j < ss[i].cssRules.length; ++j) { 
      if (ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE && ss[i].cssRules[j].name == rule) { return ss[i].cssRules[j]; } 
     } 
    } 
    return null; 
} 
function change(anim) { 
    var keyframes = findKeyframesRule(anim), 
     length = keyframes.cssRules.length; 
    var keyframeString = []; 
    for(var i = 0; i < length; i ++) 
    { 
    keyframeString.push(keyframes[i].keyText); 
    } 
    var keys = keyframeString.map(function(str) { 
    return str.replace('%', ''); 
    }); 
    totalCurrentPercent += currentPercent; 
    if(totalCurrentPercent > 100) 
    { 
    totalCurrentPercent -= 100; 
    } 
    var closest = getClosest(keys); 
    var position = keys.indexOf(closest), 
     firstPercent = keys[position]; 
    for(var i = 0, j = keyframeString.length; i < j; i ++) 
    { 
    keyframes.deleteRule(keyframeString[i]); 
    } 
    var multiplier = firstPercent * 3.6; 
    keyframes.insertRule("0% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 0) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 0) + "deg); background-color:red; }"); 
    keyframes.insertRule("13% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 45) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 45) + "deg); }"); 
    keyframes.insertRule("25% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 90) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 90) + "deg); }"); 
    keyframes.insertRule("38% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 135) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 135) + "deg); }"); 
    keyframes.insertRule("50% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 180) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 180) + "deg); }"); 
    keyframes.insertRule("63% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 225) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 225) + "deg); }"); 
    keyframes.insertRule("75% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 270) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 270) + "deg); }"); 
    keyframes.insertRule("88% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 315) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 315) + "deg); }"); 
    keyframes.insertRule("100% { -webkit-transform: translate(100px,100px) rotate(" + (multiplier + 360) + "deg) translate(-100px,-100px) rotate(" + (multiplier + 360) + "deg); }"); 
    circle.style.display = "inherit"; 
    circle.style.webkitAnimationName = anim; 
    window.clearInterval(showPercent); 
    currentPercent = 0; 
    showPercent = self.setInterval(function() { 
    if(currentPercent < 100) 
    { 
     currentPercent += 1; 
    } 
    else { 
     currentPercent = 0; 
    } 
    result.innerHTML = currentPercent; 
    }, 40); 
} 
button.onclick = function() { 
    circle.style.webkitAnimationName = "none"; 
    circle.style.display = "none"; 
    setTimeout(function() { 
     change("rotate"); 
    }, 0); 
} 
function getClosest(keyframe) { 
    var curr = keyframe[0]; 
    var diff = Math.abs (totalCurrentPercent - curr); 
    for (var val = 0; val < keyframe.length; val++) { 
    var newdiff = Math.abs(totalCurrentPercent - keyframe[val]); 
    if (newdiff < diff) { 
     diff = newdiff; 
     curr = keyframe[val]; 
    } 
    } 
    return curr; 
} 

Check out the experiment itself here包括描述什麼的JavaScript的每個部分做評論

這個解決方案注:

  • 我試圖做出改變功能的非硬編碼儘可能
  • 它的工作原理好吧,用於近似當前的@keyvalue百分比
  • 從一個動畫到另一個動畫的過渡只有儘可能平滑,但動畫的最近%值接近當前動畫的%,因此向動畫添加更多%定義使其更加光滑

在試圖想出瞭解決問題的方案的過程中,我發現這些有用的資源:

---編輯---

如果你只是使用CSS過渡或者你可以改變你的動畫只使用過渡相反,你可以使用this simpler approach。您可以通過複製由過渡更改的屬性來暫停過渡,將屬性設置爲這些已更改的屬性,然後刪除對其進行動畫處理的類。當然,如果您使用相同的對象進行動畫/暫停,您需要爲第一次點擊設置動畫,然後暫停點擊下一次。您可以輕鬆地做純JavaScript等同以及

注:在CSS改變屬性!important是必要的,除非你有動畫類比jQuery選擇更平整選擇,又名像div #defaultID.animationClass {,而不是隻是#defaultID.animationClass {。由於#defaultID#defaultID.animationClass都是一個水平,這個例子需要!important

--Another Edit--

有關此主題的更多信息,請my post on CSS-Tricks