2013-08-01 33 views
10

Có thể nhận/đặt phần trăm hoạt ảnh hiện tại của hoạt ảnh CSS3 @keyframes bằng javascript, jQuery hoặc một số phương tiện khác không?Nhận/đặt @keyframes tỷ lệ phần trăm/thay đổi khung hình chính hiện tại

Ví dụ: có div với lớp được gọi là .spin chỉ đơn giản xoay tròn trong vòng tròn bằng khung chính cũng được gọi là spin.

  1. Tôi đã cố gắng để có được những giá trị phần trăm hiện tại của phim hoạt hình sử dụng $('.spin').css('animation'), $('.spin').css('animation: spin'), và một vài cách khác, nhưng tất cả họ đều cảnh báo trống

  2. Tôi cũng quan tâm đến việc thay đổi hình ảnh động ban đầu tại mỗi khung hình chính xác được xác định trước% và tôi đã thử những thứ như $('.spin').css('animation', '..new definition here...')$('.spin').css('spin', '50%', '...new definition here...) không có kết quả.

Bất kỳ ý tưởng nào?

Trả lời

12

Tôi đã đạt được gần như những gì tôi muốn bằng javascript thuần túy với CSS3 của mình.

Để thử nghiệm của tôi tìm ra cách để thực hiện các mục tiêu này, tôi đã tạo một hoạt ảnh CSS3 cơ bản xoay vòng tròn quanh một đường tròn nhỏ. Mục tiêu của tôi là, khi một nút được nhấp, thay đổi nguồn gốc của hoạt hình đến vị trí mới

Để đạt được mục tiêu đầu tiên nhận được các giá trị phần trăm của hoạt hình tôi chỉ đơn giản là xấp xỉ tỷ lệ hiện tại bằng cách sử dụng setInterval sau , hiển thị phần trăm hiện tại xấp xỉ. Này chạy mỗi 40 mili giây tương ứng với thời hạn của hình ảnh động (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); 

Lưu ý về giải pháp này:

  • Nó không phải là hoàn hảo do vì quầy giữ chạy khi một tab khác được nhấp nhưng hoạt ảnh dừng lại, do đó chúng trở nên không đồng bộ hóa
  • Nó cũng bị lỗi khi nút được nhấp lâu sau lần nhấp cuối cùng. Rõ ràng các setInterval chạy lâu hơn một chút so với hình ảnh động, để họ trở nên ngày càng ít được đồng bộ hóa mỗi lần lặp
  • Tôi nhìn khắp mọi nơi cho một giải pháp hoàn hảo hơn, nhưng đã không thể đưa ra một thời điểm chưa

Để đạt được mục tiêu thứ hai trong việc thiết lập định nghĩa mới cho giá trị% của hoạt ảnh, nó cần một chút giải pháp phức tạp hơn.Sau khi rót qua hàng chục bài báo và trang web (những người quan trọng được liệt kê dưới đây), tôi quản lý để đưa ra các giải pháp sau đây:

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 bao gồm cả bình luận mô tả những gì từng phần của javascript đang làm

Ghi chú về giải pháp này:

  • tôi đã cố gắng để làm cho chức năng thay đổi như phi mã hóa cứng càng tốt
  • Nó hoạt động alright cho xấp xỉ hiện tại @keyvalue phần trăm
  • Chuyển đổi từ hình động này sang hình ảnh khác chỉ mịn như tuy nhiên đóng giá trị% gần nhất của hoạt ảnh là% hiện tại của hoạt ảnh, do đó, thêm% định nghĩa cho hoạt ảnh làm cho nó thậm chí còn mịn hơn

trong quá trình cố gắng để đưa ra một giải pháp cho vấn đề này, tôi tìm thấy những tài nguyên hữu ích:

  • RussellUresti's answer in this SO postcorresponding example khá có ảnh hưởng và rất nhiều hỗ trợ giải pháp cuối cùng của tôi
  • Để có được giá trị gần nhất dựa trên đầu vào và mảng giá trị, tôi đã sử dụng phương pháp paxdiablo trong this SO post (cảm ơn bạn)
  • This plugin, trong khi tôi không sử dụng nó bản thân mình, dường như để đạt được một rất giống nhau (mặc dù dường như không hoàn toàn như tùy biến) có hiệu lực trong jQuery

--- EDIT ---

Nếu bạn chỉ sử dụng CSS chuyển hoặc bạn có thể thay đổi hình ảnh động của bạn chỉ cần sử dụng hiệu ứng chuyển tiếp thay vào đó, bạn có thể sử dụng this simpler approach. Bạn có thể tạm dừng quá trình chuyển đổi bằng cách sao chép các thuộc tính được thay đổi bởi quá trình chuyển đổi, thiết lập các thuộc tính cho các thuộc tính đã thay đổi đó, và sau đó loại bỏ các lớp đó làm động nó. Tất nhiên nếu bạn đang sử dụng cùng một đối tượng để animate/pause, bạn sẽ cần phải tạo hiệu ứng cho nhấp chuột đầu tiên sau đó tạm dừng nó nhấp tiếp theo. Bạn có thể dễ dàng làm tinh khiết tương đương javascript cũng

Lưu ý: các !important trong các thuộc tính CSS thay đổi là cần thiết trừ khi bạn có một selector san bằng hơn cho các lớp hình ảnh động hơn bộ chọn jQuery, aka cái gì đó như div #defaultID.animationClass { như trái ngược với chỉ #defaultID.animationClass {. Kể từ #defaultID#defaultID.animationClass đều một cấp, ví dụ này đòi hỏi sự !important

--Another Edit--

Để biết thêm thông tin về chủ đề này, hãy kiểm tra my post on CSS-Tricks

Các vấn đề liên quan