4

jQueryを使用して<select>入力のイベントに関連付けられたハンドラーがあります。change

$('#myList').change(function () {
   //...
});

ユーザーTabが入力にアクセスして入力を開始すると(クリックしてドロップダウンリストを開くことなく)、ブラウザーによって動作が異なります。

  • Firefoxでは、ユーザーがまたはを押すEnterTab、他の方法で変更が選択リストから離れるまで、変更イベントは発生しません。
  • IEとChromeでは、ユーザーが何かを入力した瞬間に変更イベントが発生し、選択リストの項目が変更されます。

私のchange関数はAJAXリクエストを実行するため、ユーザーが入力中または矢印キーを使用して選択肢を選択している間は、関数に何も実行させたくないと思います。ただし、ユーザーがマウスで特定のドロップダウン要素を選択した場合、またはユーザーがEnterキーを押した場合に、changeイベントを発生させたいのです。つまり、IEとChromeをFirefoxのように動作させたいのです。

私が探している動作を取得するための(理想的には簡単な)方法はありますか?

4

3 に答える 3

2

編集:

これはあなたのすべての要件を処理するはずです - http://jsfiddle.net/yfQ3V/4/

HTML:

<select data-value="one">
    <option>one</option>
    <option>two</option>
    <option>three</option>
</select>
<span></span>

JS:

var $select = $('select');
var $span = $('span');

var onChange = function () {
    setText();
};

var onKeyDown = function () {
    $select.off('change');
    var keyCode = e.keyCode || e.which;

    if(keyCode == 13 || keyCode == 9) {
        $select.on('change', onChange).change(); 
    }
};

var onBlur = function () {
    if($select.val() != $select.data('value')) {
        setText();
    }
};

var setText = function () {
    var val = $select.val();
    $select.data('value', val);
    $span.text(val + ' - ' + new Date());   
};

$select.on('change', onChange)
       .on('keydown', onKeyDown)
       .on('blur', onBlur);
于 2012-04-11T21:32:07.460 に答える
1

tjscienceの答えに基づいた私の解決策は次のとおりです。これは jquery 関数として実装され、異なるハンドラーを使用して同じ要素に複数回バインドされた場合に機能します。

$.fn.dropDownChangeEventThatBehavesLikeFirefox = function (handler) {
/// <summary>The change() event behaviour for select boxes is different between Firefox and other browsers when using the keyboard.
/// Firefox only fires the change event when focus is lost, whereas other browsers fire the change event as soon the user uses the
/// keyboard to scroll through the select box.
/// This method should be used instead of the name jquery change() event to get consistent behaviour between Firefox and
/// other browsers (preferring the Firefox method).
/// </summary>
if ($.browser.mozilla) {
    // Firefox already behaves like we want it to, so get out of here.
    $(this).change(handler);
    return;
}

$(this).each(function () {

    var lastValue = $(this).val();

    $(this)
        .change(function () {
            var $this = $(this);

            handler.apply(this);

            lastValue = $this.val();
        })
        .keydown(function (e) {
            var $this = $(this);

            $this.off('change');
            var keyCode = e.keyCode || e.which;

            if (keyCode == 13 || keyCode == 9) {
                $this.on('change', handler).change();
            }
        })
        .on('blur click', function () {
            var $this = $(this);

            if ($this.val() != lastValue) {
                handler.apply(this);
                lastValue = $this.val();
            }
        });
});
};
于 2012-06-20T06:09:39.913 に答える
1

すべてのコントロールを同じように動作させるメソッドを作成して、<select>特定のケースごとに 1 回限りの Javascript を実行する必要がないようにしました。少しハックですが、少なくとも次の方法でコードの繰り返しを避けます。

$(function() {
    // Make select lists in Chrome and IE behave more like Firefox: when they are focused
    // but not open and the user starts typing, we don't want the "change" event to fire
    // until the user has actually selected the value they want.
    var invokePendingChanges = function () {
        /// <summary>
        /// Event handler which checks "this" select box for a code that shows that changed
        /// events have been ignored. If it finds the code, it will invoke the 'change'
        /// event on the input.
        /// </summary>
        var t = $(this);
        if (t.data('change-pending')) {
            setTimeout(function () {
                t.data('change-pending', false);
                t.change();
            }, 0);
        }
    };
    $('select')
        .keydown(function(e) {
            // If the user hit the enter key, invoke pending changes.
            if (e.which == 13) {
                invokePendingChanges.call(this);
            } else {
                var t = $(this);
                // Be aware that date('events') isn't part of the official API, so it is subject
                // to change with future versions of jQuery.
                var allHandlers = t.data('events');
                var changeHandlers = allHandlers ? allHandlers['change'] : null;
                delete allHandlers['change'];
                t.change(function() {
                    t.data('change-pending', true);
                    return false;
                });

                var revert = function() {
                    allHandlers['change'] = changeHandlers;
                    clearTimeout(timeout);
                    t.off('blur', revert);
                };
                t.on('blur', revert);
                var timeout = setTimeout(revert, 0);
            }
        })
        .blur(invokePendingChanges);
});
于 2012-06-04T18:50:24.703 に答える