VSB and Sequencer
Knockout で逐次実行 visual effect を実装。 Visual State Binding と sequencer を考案・利用。
by sukobuto
HTML
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>
<h1>Sequencer と<br/>Visual State Binding で<br/>逐次 jQuery アニメーション</h1>
<p><a href="http://slide.sukobuto.com/article/ko-effect#/8/1" target="_blank">Visual State Binding</a> で逐次アニメーションをバインドするデモです。</p>
<p>jQuery promise だとやりづらかったので、車輪の再開発かもしれませんが Sequencer という関数逐次実行のためのオブジェクトを作っています。Express.js のミドルウェアと同じようなノリです。</p>
<label>
<input type="checkbox" data-bind="checked: opened"/>
オープン/クローズ
</label>
<div class="wrapper" id="a" data-bind="visualState: { opened: opened }">
<div class="container" id="b">
<div class="item" id="c"></div>
<div class="item" id="d"></div>
<div class="item" id="e"></div>
</div>
</div>
CSS
body {
background: #578;
color: #ccc;
}
.wrapper {
padding: 20px;
background: #79a;
overflow: hidden;
border-radius: 10px;
}
.container {
padding: 20px;
background: #9bc;
overflow: hidden;
}
.item {
background: #cef;
width: 160px;
height: 40px;
margin: 20px;
}
JavaScript
/////////////////// Sequencer /////////////////////
(function() {
var sequencers = {};
/**
* 関数配列を逐次実行するためのシーケンサ
* 呼び出される関数では引数 next を受け取り、
* 処理が終わった時点で next を呼び出してください。
* @constructor
* @param {[callback]} func_array 逐次実行する関数配列
* @param {string} [group_id] 指定した場合、start したときに同じ id に属するシーケンサを停止します。
*/
function Sequencer(func_array, group_id) {
var self = this
, i = 0
, alive = true
;
function next() {
if (alive && func_array[i]) {
func_array[i++](arguments.callee);
}
}
/**
* このシーケンサを中断します。
*/
self.stop = function() {
alive = false;
};
/**
* このシーケンサを、中断したところから再開します。
*/
self.resume = function() {
alive = true;
next();
};
/**
* このシーケンサを最初から実行します。
*/
self.start = function() {
if (group_id) {
sequencers[group_id].forEach(function(seq) {
seq.stop();
});
}
i = 0;
alive = true;
next();
};
if (group_id) {
sequencers[group_id] = sequencers[group_id] || [];
sequencers[group_id].push(self);
}
}
window.Sequencer = Sequencer;
})();
//////////////// Viaual Effects ///////////////////
var $a = $('#a')
, $b = $('#b')
, $c = $('#c')
, $d = $('#d')
, $e = $('#e')
, base_duration = 'fast'
, wrapper_style = {
shown: {
width: 240,
height: 240,
padding: 20
},
hidden: {
width: 0,
height: 0,
padding: 0
}
}
, seq_open = new Sequencer([ // オープン用のアニメーションシーケンス
function(next) { $a.stop().animate(wrapper_style.shown, {complete: next}) },
function(next) { $b.stop().slideDown(base_duration, next) },
function(next) { $c.stop().fadeIn(base_duration, next) },
function(next) { $d.stop().animate({ height: 40 }, {complete: next}) },
function(next) { $d.stop().animate({ width: 160 }, {complete: next}) },
function(next) { $e.stop().slideDown(base_duration, next) }
], 'seq_group_a')
, seq_close = new Sequencer([ // クローズ用のアニメーションシーケンス
...