javascript - 获取/设置当前@keyframes 百分比/更改关键帧

标签 javascript css css-transitions css-animations

是否可以使用 javascript、jQuery 或其他方式获取/设置 CSS3 @keyframes 动画的当前动画百分比?

例如,有一个 div,其类名为 .spin,它使用也称为 spin 的关键帧简单地绕着一个圆圈旋转。

  1. 我尝试使用 $('.spin').css('animation') 获取动画的当前百分比值,$('.spin' ).css('animation: spin'),还有其他一些方法,但它们都提示为空

  2. 我也有兴趣在每个预定义的关键帧 % 处更改原始动画,并且我已经尝试过 $('.spin').css('animation', '..new definition here ...')$('.spin').css('spin', '50%', '...这里有新定义...) 无济于事.

有什么想法吗?

最佳答案

我使用纯 JavaScript 和我的 CSS3 大致实现了我想要的。

为了找到实现这些目标的方法,我创建了一个基本的 CSS3 动画,它围绕一条小圆形路径旋转一个圆圈。我的目标是,当单击按钮时,将动画的原点更改为新位置

为了实现获取动画百分比值的第一个目标,我使用以下 setInterval 简单地近似当前百分比,它显示近似的当前百分比。这每 40 毫秒运行一次,以对应动画的持续时间(毫秒/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 changed 属性中的 !important 是必需的,除非您有比 jQuery 选择器更层次化的动画类选择器,也就是 div #defaultID.animationClass { 而不仅仅是 #defaultID.animationClass {。由于 #defaultID#defaultID.animationClass 都是一个级别,因此此示例需要 !important

--另一个编辑--

有关此主题的更多信息,请查看 my post on CSS-Tricks

关于javascript - 获取/设置当前@keyframes 百分比/更改关键帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18006099/

相关文章:

javascript - 如何从 Angular JS 中的 get 请求获取输入字段中的数据?

javascript - 当 src url 在 Angular 范围内时如何加载脚本?

html - Bootstrap中div叠加跳转到另一行

css - 如何在 mozilla firefox 上获得线性渐变效果

jquery - 切换 View 时的 CSS 过渡

javascript - 在 asp.net 中,javascript 或 jquery 是否具有 Server.UrlEncode() 方法

javascript - 为什么 chrome 不为嵌入式 twitter 时间轴呈现 flexbox 定位?

html - 具有未知尺寸的动画 div 尺寸过渡

css - 为什么只有 chrome(也许还有 safari)可以很好地处理过渡(高度、宽度)?

javascript - 在动态内容上附加手动触发器的 Bootstrap 弹出窗口