CoffeeScriptでつくったクラス内でjQueryメソッドのコールバック関数を呼ぶ


前回の記事「CoffeeScriptでクラスをつくりその中にjQueryイベントを持たす」の関連、というか続きです。

前回も、thisの所在に悩まされたのですが、今回も同じような感じでハマったので一応メモ。

これに関する解は、わりとアチコチ(Stack Overflowなど)にあるのですが、この流れでハマると、その解に辿り着けない(ググってもそれが解答だと気づけない)ような気がするので、ここに書いておきます。

たとえば、以下のようにclassで作った<div>をこれまたclass内で定義したメソッドからアニメーションをさせます。

今回の例で言えば、右に移動したら(animate {‘left’:’128′}) 、下へ(animate {‘top’:’128′})、次に左へ(animate {‘left’:’128′})移動し、最後は元の位置(animate {‘top’:’0′})に戻る、といった動作です。

[サンプルプログラム]

これはjQueryのanimate()関数を呼びますが、完了時の引数にコールバック関数を仕込んで呼ぶことができます。つまり、animate()を入れ子のようにして連鎖的に呼ぶことができるのですが、そのとき、階層深くに押し込まれていくthisは、どういうコンテキストになるんだろう?って疑問が浮かびます。

現に、動かなくて、かなり四苦八苦しました。

結論としては、こうやります。

[coffee highlight=”20,21,26,27,28,29,30,31″]
$ = jQuery
$ ->

Circle = new AppMain()

class AppMain

CircleMain : null

constructor: ->
@createCircle()

createCircle: ->
@CircleMain = document.createElement ‘div’
@CircleMain.id = ‘circle_main’
#イメージを追加
_CircleImage = document.createElement ‘img’
_CircleImage.src = ‘circle.png’
@CircleMain.appendChild _CircleImage
#「->」ではなく、ファットアロー「=>」であることに注意!
@CircleMain.onclick = (e) =>
@CircleRoundMove()
#HTML body に追加
document.body.appendChild @CircleMain

CircleRoundMove: =>
#ここもファットアロー(=>)でつないでいく
$(@CircleMain).stop().animate {‘left’:’256′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘top’:’128′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘left’:’0′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘top’:’0′, ‘duration’:’600′}, =>

# end AppMain Class
[/coffee]

これ(=>)「fat arrow」と呼ぶんですね。知らなかった。「いこーる矢印」かと思ってた。超恥ずかしい。

The Little Book on CoffeeScript』によれば、

ファットアロー=>を用いることで、関数がどのようなコンテキストの下に呼ばれようとも、関数が作成されたコンテキストの下で実行されます。

つまり、関数実行時のthisで呼ばれるということらしいです。

ということは、次の例のようにanimate()のcomplete引数の関数内で、クラス内にある別の関数を呼ぶことも可能になります。

以下の例では、グルッと一周したら、今度は逆周りで元に戻る関数を呼び、(内部的には)二段階のアニメーションをしています。

[サンプルプログラム]

ソースはこちら↓

[coffee highlight=”34″]
$ = jQuery
$ ->

Circle = new AppMain()

class AppMain

CircleMain : null

constructor: ->
@createCircle()

createCircle: ->
@CircleMain = document.createElement ‘div’
@CircleMain.id = ‘circle_main’
#イメージを追加
_CircleImage = document.createElement ‘img’
_CircleImage.src = ‘circle.png’
@CircleMain.appendChild _CircleImage
#「->」ではなく、ファットアロー「=>」であることに注意!
@CircleMain.onclick = (e) =>
@CircleRoundMove()
#HTML body に追加
#document.body.appendChild @CircleMain
#指定の<div>に追加
document.getElementById(‘sample_coffee’).appendChild @CircleMain

CircleRoundMove: =>
#ここもファットアロー(=>)でつないでいく
$(@CircleMain).stop().animate {‘left’:’256′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘top’:’128′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘left’:’0′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘top’:’0′, ‘duration’:’600′}#, =>
@CircleRoundMoveReverse() # さらにクラス内の別のメンバ関数を中から呼ぶことも可能

#逆回し
CircleRoundMoveReverse: =>
$(@CircleMain).stop().animate {‘top’:’128′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘left’:’256′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘top’:’0′, ‘duration’:’600′}, =>
$(@CircleMain).stop().animate {‘left’:’0′, ‘duration’:’600′}

# end AppMain Class
[/coffee]

一応、今回もサンプル一式置いておきます。↓

sample_coffee2.zip

 

お気軽にコメントをどうぞ〜

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

コメントフィード

s