前回の記事「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]
一応、今回もサンプル一式置いておきます。↓
このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。
日々の開発作業で気づいたこと共有を。同じところで躓いている人が、 検索で辿り着けたら良いな、というスタンスで記事を書くので不定期更新になります。
コメントする