在上一篇《javascript設計模式實踐之迭代器--具有百葉窗切換圖片效果的JQuery插件(一)》里,通過採用迭代器模式完成了各初始化函數的定義和調用。 接下來就要完成各個切換效果的編寫。 先思考一下一個切換效果需要完成的操作 1.準備階段,將各個strip歸位到動畫效果開始的位置。 2.動畫效
在上一篇《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插件(三)》
代碼:戳