javascript设计模式实践之模板方法--具有百叶窗切换图片效果的JQuery插件(二)
在上一篇《javascript设计模式实践之迭代器--具有百叶窗切换图片效果的JQuery插件(一)》里,通过采用迭代器模式完成了各初始化函数的定义和调用。
接下来就要完成各个切换效果的编写。
先思考一下一个切换效果需要完成的操作
1.准备阶段,将各个strip归位到动画效果开始的位置。
2.动画效果处理。
3.执行。
3.完成。
所有的切换效果都具备上述3步操作。
既然这样就好抽象了。
可以对上述的操作进行单独定义,然后通过模板方法模式对各个操作进行调用。
所谓的模板方法模式,其实就是有这么一个方法完成一个业务流程的处理,在这个业务流程中的某些个细节则交个子对象去处理。就好比组装汽车的流水线就是一个模板,它规定了组装的流程,但是工人是跳着装,还是走着装,还是拿个设备辅助着装那就是安装者的事儿了。
按照模板方法模式编写一个基本效果对象。
var baseEffect = { prepare: function (context) { throw new Error('请重写prepare方法'); }, transform: function (context) { throw new Error('请重写transform方法'); }, execute: function (context) { this.prepare(context); return this.transform(context); } };
prepare函数:准备阶段操作。
transform函数:动画效果处理。
这两个方法其实就是各个切换效果根据自身的效果特性需要完成的细节。
execute函数就是执行操作,也是模板方法,在其中完成了对准备阶段和动画处理的流程调用,当然是先准备后进行动画效果处理流程。
按照约定,transform方法必须返回一个jquery的promise对象用来控制动画完成向外部的通知。
关于promise的使用可参考《jquery的promise实践--连续加载图片》。
基本效果对象完成后,接下编写各个实际的效果对象,并从基本效果继承,完成准备操作和动画处理的编写。
先编写从下往上移动各窗帘条strip的效果
var downToUpEffect = (function (baseEffect) { var effect = jquery.extend({}, baseEffect); var imgSrc; effect.prepare = function (context) { imgSrc = context.nextImgSrc(); for (var i = 0, $strip; $strip = context.$strips[i]; i++) { $strip.css('background-image', 'url(' + imgSrc + ')'); $strip.css('top', context.stripHeight + 'px'); } }; effect.transform = function (context) { var dfd = jquery.Deferred(); for (var i = 0, $strip; $strip = context.$strips[i]; i++) { if (i == context.$strips.length - 1) { $strip.animate({top: '0px'}, context.baseDelay + i * context.delayIncrement, function () { context.$container.css('background-image', 'url(' + imgSrc + ')'); dfd.resolve(); }); } else { $strip.animate({top: '0px'}, context.baseDelay + i * context.delayIncrement); } } return dfd.promise(); }; return effect; })(baseEffect);
可以看到,一上来,用了jquery.extend函数完成从基本效果对象的继承,书上基本都是在用构造器和原型继承的方式实现继承,但是本质上,在javascript的世界里函数是一等公民,对象实际上就是键值对的集合,没必要生搬硬套OOP的一套东西,这里用了jquery的继承方法,实际上就是将一个对象的方法复制过来生成另一个对象。
downToUpEffect对象只需关心在准备阶段,将所有的窗帘条strip的top都设到容器的下边沿处,在动画处理阶段通过jquery.animate动画方法对各个窗帘条strip的top执行从容器的下沿到上沿的动画。
每个strip的动画都会基于一个简单的计算得出有不同的延迟,这样在视觉上会产生strip是阶梯式的往上移动。
transform函数内通过jquery.deffered对象的resolve方法完成最后一个动画执行完成的通知。并且transform方法将promise返回使得上层可以对动画的完成进行吃处理。
再比如从上往下的效果对象编写
var upToDownEffect = (function (baseEffect) { var effect = jquery.extend({}, baseEffect); var imgSrc; effect.prepare = function (context) { imgSrc = context.nextImgSrc(); for (var i = 0, $strip; $strip = context.$strips[i]; i++) { $strip.css('background-image', 'url(' + imgSrc + ')'); $strip.css('top', '-' + context.stripHeight + 'px'); } }; effect.transform = function (context) { var dfd = jquery.Deferred(); for (var i = 0, $strip; $strip = context.$strips[i]; i++) { if (i == context.$strips.length - 1) { $strip.animate({top: '0px'}, context.baseDelay + i * context.delayIncrement, function () { context.$container.css('background-image', 'url(' + imgSrc + ')'); dfd.resolve(); }); } else { $strip.animate({top: '0px'}, context.baseDelay + i * context.delayIncrement); } } return dfd.promise(); }; return effect; })(baseEffect);
从上面的代码看下来,他们的结构是一致的,不同的就是准备阶段和动画处理的细节不同。
upToDownEffect的准备阶段负责把所有窗帘条strip的下沿对准容器的上沿,也就是移动容器的外面去。动画处理阶段就是把strip从上面移下来,并通过延迟造成阶梯式往下移动的效果。
其他的效果对象也是在这样的结构下完成属于效果自身的功能编码。
采用模板方法模式可以使得各个具体的效果对象中的编码只关心属于自己的东西,结构较为清晰,关注重点突出自身的业务逻辑,想到新效果只要专注新效果的实现即可。
其他效果对象的编写可参考全部代码。
下一篇继续:《javascript设计模式实践之职责链--具有百叶窗切换图片效果的JQuery插件(三)》
代码:戳