script.aculo.us义贯篇

何谓义贯?是指以义理贯穿。script.aculo.us啦,名气很大,但是,从没人开个头来分析它的原理,它是怎样实现的,前一文中分析了前面二百来行的代码,这个部分是基础,把它仔细研究了一下,机理也清楚了。上一文讲的是代码,不大看得懂。这一篇再在文字上总结一下。

表达能力有限,我分几点说,读者综合几点一想就清楚了。

一、一个effect是怎样运行起来的?

呐闷吧?!所有的effect,大多都是new一下就成了,你看:new HighLight({startcolor:'#FF0000',endcolor:'#00FF00'})。所以,从特效类的构造函数入手,就清楚了。再看那个initialize函数。不多说,一大把的那么多,关键就是一个this.start(options)。start的代码哪?在Effect.Base这个基类中,写好了的。start做了三件事:

创建render函数
触发beforeStart事件
如果this.options.sync为false,则加入到effect队列中去,就是一个add。这个add是Effect.ScopedQueue中的函数。
new->initlialize->Effect.Base.start->Effect.ScopedQueue.add,这个路线蛮长的,大伙不大容易搞清楚啊。没法,搞开发都这样。再说下去,add里面最后一句是关键:

  1. if (!this.interval)
  2. this.interval = setInterval(this.loop.bind(this), 15); 
这句代码表示:如果这个队列加入第一个元素时,就会启动定时器,每隔15ms就循环调用一下队列中每个effect对象的loop。官方注释中说,桢数最小只能是66fps,我当时就想这是什么原因,原因就在这儿了,至少15ms才能更新一次界面,也就是说,最快也要15ms才能一桢,这一除正好66。

这样,定时器事件调用队列的loop,队列的loop把当前时间值传给每个effect对象的loop,然后effect.loop调用effect.update。effect.update就是根据当前的时间值来更新界面了。

讲到这儿,还没有把这个effect倒底怎么工作讲清楚,到现在为止,还只是清楚了这个调用关系。调用过程蛮曲折的。

每个effect不是单个运行的,而是放到一个队列中统一运行的。
每个effect有一个loop,由它的loop调用update更新
effect.loop的参数为一时间值,它结合startOn,finishOn来确定是不是要列新。如果大于finishOn就说明更新要结束了。
把话说得更明白了:特效默认都交给一个队列管着,队列每15ms为每个特效对象报时间,至于哪个特效是不是更新界面,这是各自的私家事,队列并不管。所以啊,特效队列只是每次撞下钟,打个铃,哪个班要上课了,这还得各自的课程表安排呐。

二、特效队列的详情倒底是怎样的?

上面一讲,大伙都晓得,特效是交给一个队列管的,或者说是交给一个容器管的。这个容器是怎么个管理法呢,大伙肯定很急切地要知道这个东西。它就是Effect.ScopedQueue。代码不多。就三个函数:add、remove、loop。至于那个_each,这个是为继承Enumerable而写的私有函数,切记:写javascript的代码,以下划线开头的函数是私有函数,是不能公开调用的。

add将引发定时器的运行,定时器执行的函数就是队列的loop,这个loop也就几行代码,现在挖出来放这儿,我也不解释什么,大伙一瞧都明白了:

  1. loop: function() {
  2.   var timePos = new Date().getTime();
  3.   for(var i=0, len=this.effects.length;i<len;i++) 
  4.     this.effects[i] && this.effects[i].loop(timePos);
  5. }
这个Effect.ScopedQueue当真是很清楚,很明白。另外,effect.options.queue.limit,这个东西。看一下代码,注意一下就行了,不用多言了。至于pluck函数的用法,这个是prototype的基础了,详情请参见Enumerable的pluck,它的作用是把容器中每个成员的某一个属性分离出来作为数组返回。就这样。就彷佛数学中的投影。

三、所有特效的基类Effect.Base

这个东西也没什么好讲的,重点是一个start、loop,前面都讲了,它定义了几个函数:

start:它用于继承的子类在initialize中调用,用以启动特效。
render:用于呈现动画,它被loop调用,可以说是内部函数。我们不需要用到的。
loop:它被队列的loop函数调用,它会跟据当前时间来生成一个完成度百分数,render用的就是这个百分数。
cancel:取消特效,这个函数我们可能用得多。
event:用于调用在options中定义的事件处理函数。
inspect:相当于tostring。这个函数我们可能用到。
它有好几个属性,但是,它的属性我们一般不需要用到,只有在自己创建它的子类时才会用到。至于如何继承它,这是个简单的事。看一下下面写好的代码就晓得了。

不过,我还是得说一下在子类中要做哪些事:

写个initialize函数,然后在它里面调用start,用以启动特效
写个update函数,在它里面写入如何更新界面的代码。它只有一个参数:timepos。
上面两个是必需品,另外还有两个可以根据需要实现的:setup、finish。setup是在第一次更新之前调用,通常用于初始化一些自己的属性,finish是用于扫尾工作的。

四、组合动画(特效)是怎么干的

这个问题对应的代码上一文中没有分析到,这儿分析一下:

  1. Effect.Parallel = Class.create(Effect.Base, {
  2.     initialize: function(effects) {
  3.         this.effects = effects || [];
  4.         this.start(arguments[1]);
  5.     },
  6.     update: function(position) {
  7.         this.effects.invoke('render', position);
  8.     },
  9.     finish: function(position) {
  10.         this.effects.each( function(effect) {
  11.             effect.render(1.0);
  12.             effect.cancel();
  13.             effect.event('beforeFinish');
  14.             if (effect.finish) effect.finish(position);
  15.             effect.event('afterFinish');
  16.         });
  17.  } 
  18. });
代码不多,但是很巧妙,想不到就这样给解决了。它的巧妙之处在于,队列只负责管报时。巧妙啊,说不出来的巧。用法简单:
  1. new Parallel([new XXX(),new yyy(),new zzz(),……],options)
其中xxx,yyy,zzz是特效类,Parallel的第一个参数是特效数组,所有特效对象共享一个options。不过,每个特效对象并不单独触发事件,所有特效对象都只执行一次相关的事件。

数组中的特效是串联执行,并不是并行执行的。这个要说清楚了。

五、options.from/options.to与update

from/to倒底有用没,从用户角度来说,很显然,当然有作用,从哪儿变到哪嘛,但是,如果有两个量都要变,比如同时要变width、height,这时就不用设from、to了。from/to的默认值是0/1。它们在代码中只用了一次,就是在render中:

  1. 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';
render的参数是个百分数,但是,传到update时又是实际值了,这个地方最巧妙的是,如果设了from/to,那么,就是实际值,如果没有设,那么还是百分数。这个代码怎么能写得这么巧妙呢?真是巧啊。所以,了解了这个问题,这时再来看update,我们就有了新了感悟。新的理解。

六、Effect.Tween

这个玩意是script.aculo.us的新产品。作用是让一个对象的某属性从from变到to。中间是渐变的。就这样。这个东西是新加入的功能,网上关于它的资料少,官方好像也没有使用说明,至少我没找到,我写个示例代码吧。

  1. new Effect.Tween('div1',50,60,function(value){this.style.width=value+'px';})
关于Tween的用法,关键是最后一个参数,最后一个参数可以是一个函数,也可以是一个属性,不过,如果属性有单位,那么还是得用函数的。Effect.Tween通用用法如下:
  1. new Effect.Tween(object,from,to,options,method)
object:可是元素的id,可以是任意对象,from是起始值,to是最终值。

options:就是一般特效所传入的那个options。它可以省略。

method:要改变的属性,或一个函数。它不可省略。

Effect.Tween在使用上有一些玄妙,这需要自己去看一下源代码了,这儿就不贴代码了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值