动态创建和应用CSS3动画

3
在jQuery中,.animate()函数不能对所有CSS3可动画属性进行动画处理(例如background-color)。是否有一种不错的标准方法来动态创建、应用和删除页面元素的CSS3动画效果?
我目前正在遵循这里的示例,但感觉这样做很笨拙。虽然它能够工作,但我更希望有更好的解决方案(比如使用库等)。

请查看bounce.js - bumpy
这并没有提到background-color或其他jquery无法完成的事情。我是不是漏掉了什么,还是bounce.js是jquery.animate()的另一种实现方式? - dlkulp
你能否只使用addClass、removeClass并在CSS中设置动画? - Steve K
动画本身需要是动态的。 - dlkulp
1个回答

2

是的,我们可以动态地在页面中为元素创建、应用和移除CSS3动画。

要动态创建动画,我们需要使用insertRuleaddRule函数添加@keyframes规则并将其附加到样式表中。一旦动画被附加,将其应用于元素非常简单,我们只需要通过内联样式将所需的属性值设置为animation属性即可。当需要移除动画时,只需要将其值设回null即可。

在以下代码片段中,我首先插入了一个动画并在加载时将其应用于元素。当动画开始时,元素会触发animationstart事件。在此事件监听器中,我获取正在进行动画的元素的outerHTML,并打印出来以显示内联样式的存在;然后在动画结束时(使用animationend事件监听器),我移除了内联样式,并打印了之后的outerHTML,以显示它不再具有动画。

没有其他更简单的方法可以动态创建CSS3动画。所有可能的解决方案都涉及使用基本的insertRuleaddRule或特定于关键帧的appendRule函数(用于将规则附加到现有关键帧)来创建和附加@keyframes到样式表中。

var elm = document.querySelector('.to-animate');
var op = document.querySelector('.output');

var animName = "shake-up-down",
  animDuration = "3s",
  animTiming = "linear",
  animFillMode = "forwards",
  animIteration = "3";

var ruleText = "0% {transform: translateY(0px);}";
ruleText += "25% {transform: translateY(10px);}";
ruleText += "75% {transform: translateY(-10px);}";
ruleText += "100% {transform: translateY(0px);}";


/* From David Walsh's blog */
function addCSSAnimRule(sheet, name, rules, index) {
  if ("insertRule" in sheet) {
    sheet.insertRule("@keyframes " + name + "{" + rules + "}", index);
  } else if ("addRule" in sheet) {
    sheet.addRule("@keyframes " + name, rules, index);
  }
}

/* Self written */
function applyAnimation(elm, name, duration, timing, iteration, fillmode) {
  elm.style["animation"] = name + " " + duration + " " + timing + " " + iteration + " " + fillmode;
  
  /* or if you want to set them individually, comment the above line and uncomment this
  elm.style["animationName"] = name;
  elm.style["animationDuration"] = duration;
  elm.style["animationTimingFunction"] = timing;
  elm.style["animationIterationCount"] = iteration
  elm.style["animationFillMode"] = fillmode;*/
}

addCSSAnimRule(document.styleSheets[0], animName, ruleText, 0);
applyAnimation(elm, animName, animDuration, animTiming, animIteration, animFillMode);

/* to print output */

elm.addEventListener("animationstart", function(e) {
  op.textContent = "Animation " + e.animationName + " has started.";
  op.textContent += "\n\nElement's Outer HTML: \n";
  op.textContent += elm.outerHTML;
  op.textContent += "\n\n------------------------------------------------------------------------------";
});

elm.addEventListener("animationend", function(e) {
  elm.removeAttribute("style"); /* remove the animation */
  op.textContent += "\nAnimation " + e.animationName + " has ended.";
  op.textContent += "\n\nElement's Outer HTML: \n";
  op.textContent += elm.outerHTML;
  op.textContent += "\n\n------------------------------------------------------------------------------";
});
.to-animate {
  height: 100px;
  width: 100px;
  margin: 10px;
  border: 1px solid red;
}
<div class='to-animate'></div>
<pre class='output'></pre>

该方法可用于动态创建和使用任何类型的动画。下面的代码片段创建并添加了一个 background-color 动画。

var elm = document.querySelector('.to-animate');
var op = document.querySelector('.output');

var animName = "bgColor",
  animDuration = "4s",
  animTiming = "linear",
  animFillMode = "forwards",
  animIteration = "3";

var ruleText = "0% {background-color: red;}";
ruleText += "25% {background-color: orange;}";
ruleText += "50% {background-color: yellow;}";
ruleText += "75% {background-color: pink;}";
ruleText += "100% {background-color: red;}";


/* From David Walsh's blog */
function addCSSAnimRule(sheet, name, rules, index) {
  if ("insertRule" in sheet) {
    sheet.insertRule("@keyframes " + name + "{" + rules + "}", index);
  } else if ("addRule" in sheet) {
    sheet.addRule("@keyframes " + name, rules, index);
  }
}

/* Self written */
function applyAnimation(elm, name, duration, timing, iteration, fillmode) {
  elm.style["animation"] = name + " " + duration + " " + timing + " " + iteration + " " + fillmode;

  /* or if you want to set them individually, comment the above line and uncomment this
  elm.style["animationName"] = name;
  elm.style["animationDuration"] = duration;
  elm.style["animationTimingFunction"] = timing;
  elm.style["animationIterationCount"] = iteration
  elm.style["animationFillMode"] = fillmode;*/
}

addCSSAnimRule(document.styleSheets[0], animName, ruleText, 0);
applyAnimation(elm, animName, animDuration, animTiming, animIteration, animFillMode);

/* to print output */

elm.addEventListener("animationstart", function(e) {
  op.textContent = "Animation " + e.animationName + " has started.";
  op.textContent += "\n\nElement's Outer HTML: \n";
  op.textContent += elm.outerHTML;
  op.textContent += "\n\n------------------------------------------------------------------------------";
});

elm.addEventListener("animationend", function(e) {
  elm.removeAttribute("style"); /* remove the animation */
  op.textContent += "\nAnimation " + e.animationName + " has ended.";
  op.textContent += "\n\nElement's Outer HTML: \n";
  op.textContent += elm.outerHTML;
  op.textContent += "\n\n------------------------------------------------------------------------------";
});
.to-animate {
  height: 100px;
  width: 100px;
  margin: 10px;
  background-color: red;
}
<div class='to-animate'></div>
<pre class='output'></pre>


跨浏览器版本:

这里提供了一个跨浏览器版本,使用Prefix free库公开的方法来支持旧版浏览器。它已在IE10+、Edge、Chrome v50(dev-m)、Firefox v43和Opera v35上进行了测试。对于带前缀的版本,我们在Win 10上的Safari 5.1.7上进行了测试。


1
我喜欢这个。+1唯一缺少的是跨浏览器支持。(或者至少对于CSS3兼容的浏览器使用供应商前缀。)您可以使用David的另一个片段来实现:检测供应商前缀 - Bram Vanroy
@BramVanroy:非常感谢。我实际上在犹豫是否使用David的脚本,还是使用像prefix-free这样的库,让他们找到浏览器所需的前缀。我想我会选择第二条路,以避免使代码更加臃肿(但您的评论绝对有价值)。 - Harry
我不知道PrefixFree能够在DOM更改/样式规则插入后添加供应商前缀,但我查了一下,你确实是对的!(可能需要它的插件才能正常工作。) - Bram Vanroy
是的 @BramVanroy,它还公开了一个变量(PrefiFree.prefix),我们可以使用它来获取适用于用户浏览器的前缀。 - Harry
@BramVanroy: 这个就是我所说的。使用Prefix free暴露的函数和变量。在所有浏览器中经过测试并且可正常工作(前缀测试是在旧版本的Safari中完成的)。 - Harry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接