第四十二课:基于CSS的动画引擎

由于低版本浏览器不支持css3 animation,因此我们需要根据浏览器来选择不同的动画引擎。如果浏览器支持css3 animation,那么就使用此动画引擎,如果不支持,就使用javascript的动画引擎。

首先,我们看一下判定条件,方便切换。前面说过,浏览器把所有事件类型的构造器放在window上,只不过不可遍历。我们用Object.getOwnPropertyNames(window),可以得到window对象中的所有属性,然后再filter一下,就能得到所有的事件构造器了。最后,我们通过判断如果存在window.AnimationEvent或window.WebKitAnimationEvent就可以使用我们基于css的动画引擎了。

Object.getOwnPropertyNames(object)方法返回object对象自己的属性的名称。 一个对象的自己的属性是指直接对该对象定义的属性,而不是从该对象的原型继承的属性。返回值是一个数组,其中包含object对象自己的属性的名称,而且object的可枚举的和不可枚举的属性和方法都返回。 若要仅返回可枚举的属性和方法的名称,可使用 Object.keys 函数

另一个方法也可以判断,通过判定有没有keyframe样式规则的构造器。它也是放在window上的,我们可以通过这样的等于来判断:var ok = window.MozCSSKeyframeRule || window.WebKitCSSKeyframeRule || window.CSSKeyframeRule;

用css实现动画引擎有以下几个好处:

(1)不用你计算原始值,它自行内部计算。

(2)颜色值不用你转换为RGB数组。

(3)如果想做动画倒带,直接设置animation-iteration-count为2,animation-direction为alternate就行了。

(4)像hide这个特效,需要我们在动画结束时,将进行动画的样式还原为初始值,在css3中,我们只需要animation-fill-mode设置为backwards就行了。

(5)对于动画的暂停和继续,其实就是控制animation-play-state的值。

css动画引擎在操作元素进行动画时,是通过添加类名或插入样式规则实现的,添加类名,我们可以通过el.classList.add()来操作。动态插入样式就有点难度了,我们需要了解相关的API。

在浏览器中,有两个元素能生产样式表,link和style。我们可以访问它们的sheet属性(样式表对象),此属性下面有一个cssRules属性(CSSRules类数组对象),它的值包含所有的样式规则。

在css中,样式规则至少有5种类型,这里我们只讲跟我们动画引擎有关的两种类型:CSSStyleRule和CSSKeyframesRule。

.move { animation:move 4s linear;}     这就是CSSStyleRule

@keyframes move { from{ margin-left:-20%;}     to{margin-left:100%; }   }    CSSKeyframesRule

CSSStyleRule,我们可以通过它的selectorText取得指定的样式规则,比如这里的selectorText的值就是.move。

CSSKeyframesRule,我们可以通过它专有的name属性判定,比如这里的name就是move。

下面,我们来看下操作样式规则的方法:

var styleElement;

function insertCSSRule(rule){    //当插入样式规则

  if(styleElement){    //如果之前已经插入过了,那么就进入if

    var number = 0;

    try{

      var sheet = styleElement.sheet;     //样式表对象

      var cssRules = sheet.cssRules;  //样式规则对象

      number = cssRules.length;   //有多少样式规则

      sheet.insertRule(rule , number);   //把rule插入到样式表对象中,位置在number处。

    }catch(e){

      $.log(e.message + rule);   //抛出错误

    }

  }else{     //如果是第一次插入

    styleElement = document.createElement("style");   //创建一个新的style

    styleElement.innerHTML = rule;      //把样式规则放入这个style标签中

    document.head.appendChild(styleElement);   //把这个style插入到页面中

  }

}

function deleteCSSRule(ruleName , keyframes){      //第一个参数代表要删除的样式的名字,第二个参数代表要删除的样式是否是CSSKeyframesRule规则的,是就是true

  var prop = keyframes ? "name" : "selectorText";       //这里我们假设删除的是keyframes的样式,比如:deleteCSSRule("move",true)

  var name = keyframes ? "@keyframes" : "cssRule";

  if(styleElement){    //当样式存在时,才能删除

    var sheet = styleElement.sheet;

    var cssRules = sheet.cssRules;

    for(var i=0,n=cssRules.length;i<n;i++){   //遍历样式规则

      var rule = cssRules[i];

      if(rule[prop] ===ruleName){     //这里的prop="name",ruleName="move",因此如果sytle存在@keyframes move样式定义,rule[prop]==="move"

        sheet.deleteRule(i);    //删除样式表对象中的此样式规则。

        break;

      }

    }

  }

}

接着,就是三个重要的内容函数:

startAnimation,nextAnimation与stopAnimation。

startAnimation方法,用于立即执行此元素的动画,具体做法是先把传进来的参数构建成两个样式规则,第一个样式规则就是普通的CSSStyleRule,它的selectorText是一个类名,比如上面的.move,第二个样式规则是CSSKeyframesRule,它的name就是@keyframes后面的值,比如上面的move。然后,把这两个样式规则添加到页面上去。然后绑定animationend事件,最后,给要运动的元素el添加此类名,el.classList.add(className),比如上面的move。这时,el元素就会根据这两个样式规则进行动画操作,等这个动画操作结束后,就会触发animationend事件回调函数。在这个事件回调函数中,会先把元素动画的最终状态的样式全部赋给el元素的style属性中,然后移除el元素的此类名,el.classList.remove(className),这里如果不先保存动画最终状态的样式给元素el.style,当移除el元素的此类名className时,元素el会恢复到最初的状态,而不会保存动画最终状态的样式。然后移除第二个样式规则,也就是@keyframes定义的样式。最后,检查是否有其他动画元素在排队,如果有,就调用nextAnimation方法

nextAnimation(),会先判断当前是否有动画在执行,如果没有就从队列中找出一个动画对象进行动画操作(调用startAnimation),如果有,就不做任何处理。当然在队列中,如果此动画对象有延迟操作,就用setTimeout来延迟操作动画的执行。

stopAnimation用于停止动画的操作,它传入一个类名,也就是上面的move,如果当前只有一个元素引用了这个类名,那么就会在页面中删除此类名定义的样式,这里就是.move{}中的所有内容,以及keyframe定义的样式,这里就是@keyframes move{}定义的样式。如果有两个或者多个元素引用了这个类名,那么,只会把这个count减一,然后不做任何操作,直到count=0时,也就是没有元素引用这个类名时,才会删除上面的两个样式。

基于css的动画引擎就是这么简洁。但是它也有缺点,比如:它对scrollTop,scrollLeft的动画就无能为力了。此外,我们也无法对canvas元素里面的矢量图形进行动画操作。

最后,CSS3还支持transform2D和transform3D,javascript通过WebGL来实现3D效果,这些都需要用到矩阵方法进行复杂的运算,希望某一天,我加入的公司能够研究这一块。

加油!

时间: 2024-10-24 01:13:28

第四十二课:基于CSS的动画引擎的相关文章

NeHe OpenGL教程 第四十二课:多重视口

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十二课:多重视口 多重视口 画中画效果,很酷吧.使用视口它变得很简单,但渲染四次可会大大降低你的显示速度哦:) 欢迎来到充满趣味的另一课.这次我将向你展示怎样在单个窗口内显示多个视口.这些视口在窗口模式下能正确的调整大小.其中有

JAVA学习第四十二课 — 泛型(二)—泛型接口&amp;&amp;通配符应用

一.泛型接口 interface Inter<T>{ public void show(T t); } class InterImple implements Inter<String>{//知道是字符串类型 public void show(String str){ System.out.println("show "+str); } } class InterImple_2<Q> implements Inter<Q>{//不知道是什

AGG第四十二课 Blitting an image over another with transparency

问题: I've managed to blit a loaded image onto another through the method "copy_from(...)" of renderer_base. I'd like to know how can i blit the same image and also specifying a color that will NOT overwrite the pixels of the destination image ( a

第四十二课 KMP算法的应用

思考: replace图解: 程序完善: DTString.h: 1 #ifndef DTSTRING_H 2 #define DTSTRING_H 3 4 #include "Object.h" 5 6 namespace DTLib 7 { 8 9 class String : Object 10 { 11 protected: 12 char* m_str; 13 int m_length; 14 15 void init(const char* s); 16 bool equa

猫猫学IOS(四十二)UI之核心动画CAAnimationGroup以及其他

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents 效果: 代码: 很简单,不多说,就是把一堆动画放一起,看代码. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // 平移动画 CABasicAnimation *a1 = [CABasicAnimation animation]; a1.k

NeHe OpenGL教程 第二十二课:凹凸映射

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十二课:凹凸映射 凹凸映射,多重纹理扩展: 这是一课高级教程,请确信你对基本知识已经非常了解了.这一课是基于第六课的代码的,它将建立一个非常酷的立体纹理效果. 这一课由Jens Schneider所写,它基本上是由第6课改写而来

【C++探索之旅】第一部分第十二课:指针一出,谁与争锋

内容简介 1.第一部分第十二课:指针一出,谁与争锋 2.第一部分第十三课预告:第一部分小测验 指针一出,谁与争锋 上一课<[C++探索之旅]第一部分第十一课:小练习,猜单词>中,我们用一个小游戏来总结了之前几课学习的知识点. 现在,终于来到第一部分的最后一个知识点了,也是C++的基础部分的最后一个讲题.之后进入第二部分,就会开始面向对象之旅.因此,这一课也注定不平凡.系好安全带吧,因为马力要加足了! 指针这个C系语言的难点(著名的C语言里也有指针),令无数英雄"尽折腰",也

程序员的奋斗史(四十二)——大学断代史(六)——我与图书馆

文/温国兵 作为一个爱读书之人,图书馆简直是人间天堂.反之,不过地狱. 读书的好处在于,可以穿越古今中外,超越时间和空间的界限,到达你想到达的地方.你可以回到唐朝和诗仙酌酒言欢,可以回到战国和庄子高谈庄周梦蝶.鲲鹏之硕,可以回到18世纪的法国聆听哲人卢梭的教导,可以回到19世纪的德国瞻仰尼采的智慧,可以回到20世纪的中国感受王小波的特立独行,可以回到春秋时期领略老子的道,可以回到20世纪感受徐志摩的唯美诗歌--书中自有黄金屋,书中自有颜如玉,从书中可以获取到广阔的精神食粮,指引着我们前进,教导我

第四十二章

第四十二章1 道生“肾” 道生一,一生二,二生三,三生万物. 道生出混沌之气,混沌之气分出阴阳,阴阳又交汇出新的物质,从而生出万物. 道在我们身体内体现为“肾精”,要保护好.各位朋友大家好,今天我们接着来聊<道德经>.我们来看看老子带给我们什么样新的人生启发了,每天启发一点,天天进步.今天我们开始学习第四十二章,非常开心.因为我们<道德经>已经学习到一半的位置了,因为整个八十一章,我们学习到第四十二章了,过了一半了,这时间也是飞快的.我之前预计3年,我估计现在2年差不多讲完了.因为