Как обнаружить поддержку `focusin`?

Благодаря совершенным убийствам мы можем использовать следующий код JavaScript для обнаружения поддержка мероприятия:

function hasEvent(ev) {
    var elem = document.createElement('a'),
        type = 'on' + ev,
        supported = elem[type] !== undefined;
    if (!supported) {
        elem.setAttribute(type, 'return;');
        supported = typeof elem[type] === 'function';
    }
    elem = null;
    return supported;
}

Это работает примерно в единственном случае, когда мне это нужно: обнаружение поддержки mouseenter; hasEvent('mouseenter') вернет false в Chrome, Firefox и т. д., как и должно быть.

Но теперь я пытаюсь исправить браузеры, которые не поддерживают события focusin и focusout. Согласно PPK, это просто Firefox. К сожалению, Chrome и Safari указаны как имеющие неполную поддержку по следующей причине:

Safari и Chrome запускают эти события только с помощью addEventListener; не с традиционной регистрацией.

В целом, это нормально; В любом случае я бы использовал только addEventListener. Однако это действительно означает, что обнаружение поддержки через elem.onfocusin !== undefined не будет работать. Я проверил это, и это правда:

<p>Do I support <a href="#">focusin</a>?</p>

<script>
var elem = document.getElementsByTagName('p')[0];

// hasEvent method defined here
function listener() {
    var response = hasEvent('focusin') ? 'Yes!' : 'No...';
    alert(response);
}

elem.addEventListener('focusin', listener, false);
</script>

Приведенные выше предупреждения No... в Chrome! Есть ли способ определить, поддерживает ли браузер focusin, не используя анализ браузера?


person sdleihssirhc    schedule 07.09.2011    source источник
comment
есть ли разница между mouseenter и mouseover? или фокус и фокус? или фокус и размытие?   -  person Ibu    schedule 07.09.2011
comment
@Ibu mouseenter не пузырится, а mouseover делает; focusin/focusout делать пузырь, focus/blur не делать.   -  person sdleihssirhc    schedule 07.09.2011
comment
Другим важным фактом является то, что объекты событий focusin и focusout имеют свойство relatedTarget, которое указывает на элемент, потерявший/получивший фокус.   -  person Dmitry Pashkevich    schedule 25.02.2013


Ответы (3)


Здесь используется тот факт, что вызов focus() вызывает focusin: http://jsfiddle.net/pimvdb/YXeD3/ .

Элемент должен быть видимым и вставленным в DOM, иначе focusin по какой-то причине не сработает.

var result = (function() {
    var hasIt = false;

    function swap() {
        hasIt = true; // when fired, set hasIt to true
    }

    var a = document.createElement('a'); // create test element
    a.href = "#"; // to make it focusable
    a.addEventListener('focusin', swap, false); // bind focusin

    document.body.appendChild(a); // append
    a.focus(); // focus
    document.body.removeChild(a); // remove again

    return hasIt; // should be true if focusin is fired
})();
person pimvdb    schedule 07.09.2011
comment
Мне нравится эта идея, но этот метод обнаружения немного навязчив, поскольку он меняет активный элемент на странице. - person Gyum Fox; 24.03.2015
comment
Этот ответ был бы лучше, если бы он также предотвращал получение фокуса временным элементом привязки. Тогда у него не было бы заметных побочных эффектов. (Наподобие кражи фокуса. Что, если элемент на странице попытается сфокусироваться при загрузке страницы?) - person Chris Calo; 16.08.2015

focusin и focusout должны быть запущены ДО того, как целевой элемент получит фокус, порядок событий также кажется ошибочным

http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order

в настоящее время только IE работает в соответствии со спецификацией:

Chrome/Safari:
focus
focusin
DOMFocusIn
blur
focusout
DOMFocusOut
focus
focusin
DOMFocusIn

Opera 12:
focus
DOMFocusIn
focusin
blur
DOMFocusOut
focusout
focus
DOMFocusIn
focusin

IE 8:
focusin
focus
focusout
focusin
blur
focus

Firefox 14:
focus
blur
focus
person 4esn0k    schedule 30.07.2012
comment
Что ж, спецификация написана в соответствии с поведением IE, так что в этом нет ничего удивительного. - person Louis-Rémi; 31.07.2012
comment
но поведение IE хорошее, т.е. поддержка event.toElement/event.fromElement, другие браузеры не поддерживают относительныйTarget/toElement/fromElement для этого события - person 4esn0k; 31.07.2012

Вы можете проверить ("onfocusin" in document).

Преимущество этого метода в том, что он легкий и ненавязчивый, и он сообщит вам, поддерживает ли браузер событие focusin (извините, не в Chrome)

Вы можете использовать следующий код, чтобы получить то же поведение, что и событие focusin во всех браузерах (IE9+, Chrome, Firefox, Edge):

var eventName, useCapture;
if ("onfocusin" in document) {
  eventName = "focusin";
  useCapture = false;
} else {      
  eventName = "focus";
  useCapture = true;
}

document.body.addEventListener(eventName, function( event ) {
    event.target.style.background = "pink";    
  }, useCapture);

Скрипт JS здесь: https://jsfiddle.net/d306qm92/2/

Дополнительная информация об обходном пути Firefox здесь: https://developer.mozilla.org/en-US/docs/Web/Events/focus#Event_delegation

ОБНОВЛЕНИЕ. Как сказано выше, в тесте Chrome ошибочно указано "false", тем не менее пример кода будет работать так, как предполагалось, поскольку Chrome поддерживает оба метода (focusin и focus с useCapture).

person Gyum Fox    schedule 29.04.2016
comment
Это не имеет значения для Chrome, потому что с Chrome у вас не будет необходимости использовать фокус и фокус. например, изменение видимости js addEventListener - person Thomas Aumaitre; 29.12.2020