プロが教える店舗&オフィスのセキュリティ対策術

はじめまして。
現在 prototype.js 1.4.0 を利用して、Web ページの作成を行っているのですが、イベントの登録 (Event.observe)でやりたいことと、異なる動作になってしまい困っているところです。

[ やりたいこと ]
javascript側で動的に生成した各要素 (div) に対して moueover & mouseout のイベントを割り当てる。mouseover 時には background の値を変え mouseout 時には background の値を元(transparent)に戻す。

[ 困っていること ]
各要素のmouseover & mouseout 時には各要素の背景色が変更されるはずなのに、一番最後に生成した要素の背景が変更されてしまう。

[ コード ]
<html>
<head>
<script type="text/javascript" src="prototype.js" ></script>
<script type="text/javascript">
view = new Class.create();
view.prototype = {
initialize:function() {
var view = $('viewContents');
var idName = 'test';

for (var i=0; i<10; i++) {
var id = idName + i;
var d = document.createElement('div');
d.id = id;
d.innerHTML = id;
view.appendChild(d);

Event.observe(d,'mouseover',function() {d.style.background='#aaa';}.bind(this),false);
Event.observe(d,'mouseout' ,function() {d.style.background='transparent';}.bind(this),false);
Event.observe(d,'click' ,function() {alert(d.id);}.bind(this),false);
}
}
}
</script>
</head>
<body>
<p><input type="button" onclick="new view();" value="取得"></p>
<div id="viewContents"></div>
</body>
</html>

となります。
なにか基本的なところが間違っているのでしょうか?
よろしくお願いいたします。

A 回答 (2件)

#1>…ということでよろしいのでしょうか?


私の理解している処(なので、間違っているかも知れません、話半分で聴いて下さい)では、
コールバック関数にbind(this)すると言うことは、this(この場合は、view)の中でその関数を呼び出すことです。
ここで呼び出される関数は、定義された時の(dの)値を中味として実行されるのではなくて、呼び出された時にその(dの)中味を実行するので、ループが終了した最後のd(ループで置き換えられるから)が使われるのだと思います。(つまり変数名でアクセスされその定義した時の中味にアクセスされるのではない)
なので、この場合、dを1つの変数でアクセスするのでなく、それぞれのオブジェクトでアクセスできた方がいいとわかります。
それで、this.div にしてみました。
view のままでも配列にして保持するとか
Event.observe を使わないで
d.onclick=function(){alert(this.id)};
のようにもできると思います。
また、
click:function(){
alert(this.div.id);
}
のようにメソッド定義をして
Event.observe(this.div,'click', this.click.bind(this),false);
のようにもできると思います。(どちらかというと、こちらの方がbindしてるという感じになるような)
    • good
    • 0
この回答へのお礼

丁寧なご説明ありがとうございます。
>呼び出された時にその(dの)中味を実行するので、ループが終了した最後のd(ループで置き換えられるから)が使われるのだと思います。
で、何とかですが理解することができました。

ありがとうございました。

お礼日時:2006/09/19 23:20

prototype.js って普段使っていないのでオオボケかましてたらすみません。


>基本的なところが間違っているのでしょうか?
質問にあるソースでbind(this) されている'this' は、何かということを勘違いされているのだと思います。
なるべく、元の形を活かして書き直してみました。
----------------------------------------------------------------
<script type="text/javascript">
cDiv = new Class.create();
cDiv.prototype = {
initialize:function(id, html){
this.div = document.createElement('div');
this.div.id = id;
this.div.innerHTML = html;
//better? : bind -> bindAsEventListener
Event.observe(this.div,'mouseover', function(){this.div.style.background='#aaa';}.bind(this),false);
Event.observe(this.div,'mouseout', function(){this.div.style.background='transparent';}.bind(this),false);
Event.observe(this.div,'click', function(){alert(this.div.id);}.bind(this),false);
}
};
view = new Class.create();
view.prototype = {
initialize:function() {
var view = $('viewContents');
var idName = 'test';

for (var i=0; i<10; i++) {
var id = idName + i;
var div = new cDiv(id, id).div;
view.appendChild(div);
}
}
};
</script>
    • good
    • 0
この回答へのお礼

書き直していただいたコードで実行することにより、期待した動作になりました。ありがとうございます。

>bind(this) されている'this' は、何かということを勘違いされているのだと思います。
ですが、動的に生成した要素の Class オブジェクト一つ一つにイベントを登録しないといけないのに、ひとつしか生成していない View オブジェクトにイベントを割り当てたために、おかしな動作になってしまった。

ということでよろしいのでしょうか?

お礼日時:2006/09/19 09:17

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!