更新:( 要約、フィドル、報奨金)
この質問はあまり注目されていないので、私はそれに少し担当者を費やすつもりです. 私は、回答と質問の両方で過度に冗長になる傾向があることを知っています。それが、私が先に進んでこの fiddleを設定した理由です。これは、私の見解では、バブリングchange
イベントに近づくために現在使用しなければならない種類のコードの適切な表現です。私が解決しようとしているいくつかの問題:
- フォーカスを失っていない限り、
pseudo-change
イベントは select 要素では発生しません。場合によっては、新しい値を選択したときにクライアントをリダイレクトする必要があります。どうすればこれを達成できますか? - ハンドラは、ラベルがクリックされたときと、チェックボックス自体がクリックされたときの両方で呼び出されます。それ自体はあなたが期待することですが、イベントのバブリングにより、どの要素がクリックされたかを判断することは (AFAIK) 不可能です。
realTarget
IE のイベント オブジェクトにはプロパティがありません。 - ラベルをクリックしてIEのチェックボックスの状態を変更する
checked
と、すべて問題ありませんが(厄介な回避策が必要ですが)、チェックボックスを直接クリックするとハンドラーが呼び出されますが、チェックされた状態は変更されません。 2回目。その後、値は変更されますが、ハンドラーは呼び出されません。 - 別のタブに切り替えて再び戻ると、ハンドラーが複数回呼び出されます。チェックされた状態が実際に変化した場合は 3 回、チェック ボックスを 1 回だけ直接クリックした場合は 2 回。
上記の問題の 1 つまたは複数を解決するのに役立つ情報をいただければ幸いです。jQueryタグを追加することを忘れていませんでした。純粋な JS が好きなので、純粋な JS の回答を探しています。
250 をはるかに超える選択要素と 20 ~ 30 のチェックボックスを含む Web ページがあります。また、ユーザーの行動を追跡し、適切な行動を取らなければなりません。したがって、何百ものリスナーを追加するのではなく、変更イベントを委任することは非常に自然なことです。
もちろん、IE - 会社のポリシー: IE8 をサポートする必要がある - は、必要なときに onchange イベントを発生させません。だから私は onchange イベントを偽造しようとしています。これまでのところ、私を本当に悩ませている1つのことを除けば、かなりうまく機能しています。イベントを登録するためにandを
使用しています。場合によっては、ユーザーが select 要素から新しい値を選択すると、スクリプトはすぐに応答する必要があります。ただし、select がフォーカスを失っていない限り、これは発生しません。onfocusin
onfocusout
これが私がこれまでに思いついたものです:
i = document.getElementById('content');
if (!i.addEventListener)
{
i.attachEvent('onfocusin',(function(self)
{
return function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
switch (target.tagName.toLowerCase())
{
case 'input':
if (target.getAttribute('type') !== 'checkbox')
{
return true;
}
return changeDelegator.apply(self,[e]);//(as is
case 'select':
self.attachEvent('onfocusout',(function(self,current)
{
return function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
if (target !== current)
{
return;
}
self.detachEvent('onfocusout',arguments.callee);//(remove closure
return changeDelegator.apply(self,[e]);
}
})(self,target));
default: return;
}
}
})(i));//(fake change event, buggy
}
else
{//(to put things into perspective: all major browsers:
i.addEventListener('change',changeDelegator,false);
}
onfocusin
イベントにバインドされたハンドラー内に別のイベントリスナーをアタッチしようとしましonclick
た。onfocusout
ATM にフォーカスがある selectのイベントを発生させました。唯一の問題は、ユーザーの 99.9% が選択をクリックするため、focusin
イベントも onclick を発生させることです。
それを回避するために、クロージャーを作成し、現在のフォーカス中の選択とその元の値を引数として渡しました。ただし、一部のユーザーはキーボードを使用し、これらのユーザーは多くの場合、値を変更せずに次の選択ボックスに移動します。新しいonclickリスナーをバインドするたびに...すべてをチェックe.type
して個別に処理するよりも簡単な方法があると思います。
例として: 追加のonclick
リスナーを含むコード: すべてのコードは最初のスニペットと同じなので、case 'select':
ブロックのみを貼り付けています
case 'select':
self.attachEvent('onfocusout',(function(self,current)
{
return function(e)
{
e = e || window.event;//(IE...
var target = e.target || e.srcElement;
if (!(target === current))
{
return;
}
self.detachEvent('onfocusout',arguments.callee);//(remove closure
return changeDelegator.apply(self,[e]);
};
})(self,target));
self.attachEvent('onclick',(function(self,current,oldVal)
{
return function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
if (target.tagName.toLowerCase() === 'option')
{
while(target.tagName.toLowerCase() !== 'select')
{
target = target.parentNode;
}
}
if (target !== current)
{//focus lost, onfocusout triggered anyway:
self.detachEvent('onclick',arguments.callee);
return;
}
var val = target.options[target.selectedIndex].innerHTML;//works best in all browsers
if (oldVal !== target.options[target.selectedIndex].innerHTML)
{
self.detachEvent('onclick',arguments.callee);
return target.fireEvent('onfocusout');
}
};
})(self,target,target.options[target.selectedIndex].innerHTML));
default: return;