Когда происходит событие «размытия», как я могу узнать, на какой фокус элемента * направлено *?

188

Предположим, я прикрепляю blurфункцию к блоку ввода HTML следующим образом:

<input id="myInput" onblur="function() { ... }"></input>

Есть ли способ получить идентификатор элемента, вызвавшего blurсобытие (элемент, по которому щелкнули) внутри функции? Как?

Например, предположим, что у меня есть диапазон, как это:

<span id="mySpan">Hello World</span>

Если я щелкну на промежутке сразу после фокусировки на элементе ввода, элемент ввода потеряет фокус. Как функция узнает, что на нее mySpanщелкнули?

PS: Если бы событие onclick диапазона произошло до события onblur входного элемента, моя проблема была бы решена, потому что я мог бы установить некоторое значение состояния, указывающее, что конкретный элемент был нажат.

PPS: фон этой проблемы заключается в том, что я хочу, чтобы внешний элемент управления автозаполнения AJAX (из активируемого элемента) запускался, чтобы показать его предложения, без немедленного исчезновения предложений из-за blurсобытия в элементе ввода. Поэтому я хочу проверить в blurфункции, был ли нажат один конкретный элемент, и если это так, игнорировать событие размытия.

Михель Боркент
источник
Это интересный вопрос, который я хотел бы увидеть в обосновании - то есть, почему вы это делаете? Каков контекст?
Рахул
Rahul и roosteronacid, я обновил вопрос как реакцию на ваши комментарии (PPS).
Михил Боркент
1
Поскольку эта информация немного устарела, см. Здесь новый ответ: stackoverflow.com/questions/7096120/…
Джонатан М

Ответы:

86

Хм ... В Firefox вы можете использовать explicitOriginalTargetэлемент, на который вы нажали. Я ожидал toElementсделать то же самое для IE, но, похоже, он не работает ... Однако вы можете извлечь недавно сфокусированный элемент из документа:

function showBlur(ev)
{
   var target = ev.explicitOriginalTarget||document.activeElement;
   document.getElementById("focused").value = 
      target ? target.id||target.tagName||target : '';
}

...

<button id="btn1" onblur="showBlur(event)">Button 1</button>
<button id="btn2" onblur="showBlur(event)">Button 2</button>
<button id="btn3" onblur="showBlur(event)">Button 3</button>
<input id="focused" type="text" disabled="disabled" />

Предостережение: этот метод не работает для изменений фокуса, вызванных перелистыванием полей с помощью клавиатуры, и вообще не работает в Chrome или Safari. Большая проблема с использованием activeElement( за исключением IE) является то , что она не постоянно обновляется до тех пор , послеblur того, как событие было обработано, и может не иметь действительное значение вообще при обработке! Это может быть смягчено с помощью вариации техники, в которой Михил использовал :

function showBlur(ev)
{
  // Use timeout to delay examination of activeElement until after blur/focus 
  // events have been processed.
  setTimeout(function()
  {
    var target = document.activeElement;
    document.getElementById("focused").value = 
      target ? target.id||target.tagName||target : '';
  }, 1);
}

Это должно работать в большинстве современных браузеров (тестируемых в Chrome, IE и Firefox), с той оговоркой , что Chrome не устанавливает фокус на кнопках, которые щелкнули ( по сравнению с вкладками к).

Shog9
источник
1
Я давно искал что-то вроде ОчевидноеОригинальное Цель. Как вы это обнаружили?
Кев
3
Исследовал объект события в FireBug. FWIW, это свойство относится к Mozilla и задокументировано в MDC: developer.mozilla.org/en/DOM/event.explicitOriginalTarget
Shog9
2
Это не работает (или перестало работать?) В Firefox 3.6 и Safari 4.0.3 в Windows.
Четан С
1
@Jonathan: свойство доступно, но не обновляется при возникновении blurсобытия. Я обновил ответ с деталями. Вы пытались использовать activeElement для этого в Chrome или Firefox? Это дает вам размытый элемент ...
Shog9
1
На самом деле не работает на FF 31 :licitOriginalTarget показывает текущую цель размытия, document.activeElement имеет значение null для события размытия.
Адриан Мэр
76

2015 ответ : в соответствии с событиями пользовательского интерфейса , вы можете использовать relatedTargetсвойство события:

Используется для идентификации вторичного EventTargetобъекта, связанного с событием Focus, в зависимости от типа события.

Для blurсобытий,

relatedTarget: цель, получающая фокус.

Пример:

function blurListener(event) {
  event.target.className = 'blurred';
  if(event.relatedTarget)
    event.relatedTarget.className = 'focused';
}
[].forEach.call(document.querySelectorAll('input'), function(el) {
  el.addEventListener('blur', blurListener, false);
});
.blurred { background: orange }
.focused { background: lime }
<p>Blurred elements will become orange.</p>
<p>Focused elements should become lime.</p>
<input /><input /><input />

Примечание. Firefox не будет поддерживать relatedTargetдо версии 48 ( ошибка 962251 , MDN ).

Ориоль
источник
Firefox не имеет поддержки, но есть тикет: bugzilla.mozilla.org/show_bug.cgi?id=687787
sandstrom
4
Теперь это имеет. Смотрите здесь .
rplaurindo
1
люблю веб-сообщество, теперь все намного проще ^ _ ^
am05mhz
7
Отличное решение. К сожалению, relatedTargetвернется, nullесли цель, получающая фокус, не является элементом ввода.
Педро Хоэль Карвалью
6
Если получающий элемент фокуса не является входным элементом, добавьте tabIndex="0"к нему атрибут, и он будет работать
Dany
19

Я решил это в конце концов с помощью таймаута для события onblur (благодаря совету друга, который не является StackOverflow):

<input id="myInput" onblur="setTimeout(function() {alert(clickSrc);},200);"></input>
<span onclick="clickSrc='mySpan';" id="mySpan">Hello World</span>

Работает как в FF, так и в IE.

Михель Боркент
источник
9
Считается ли это плохой практикой в ​​мире javascript?
Михил Боркент
1
старый пост но у меня такой же вопрос. тем не менее, это единственная вещь, которая, кажется, делает работу кросс-браузерной.
Джош
этот ответ помог мне в ТОНН, решив еще одну проблему ... Спасибо, Майкл!
Алекс
@MichielBorkent - это плохая реализация, потому что она не основана на событиях. Вы ждете определенное количество времени и просто надеетесь, что это было достаточно долго. Чем дольше вы ждете, тем безопаснее вы, но и тем больше времени вы тратите, если вам не нужно ждать так долго. Может быть, кто-то использует действительно старое / медленное устройство, и этого таймаута недостаточно. К сожалению, я здесь, потому что события не дают мне того, что мне нужно, чтобы определить, щелкает ли iframe в FireFox, но он работает для всех других браузеров. Мне так хочется использовать этот метод сейчас, хотя это плохая практика.
CTS_AE
1
Этот вопрос довольно старый, он восходит к 2008 году. Между тем, возможно, были и лучшие подходы. Можете ли вы попробовать ответ 2015 года?
Михил Боркент
16

Можно использовать событие размытия документа вместо размытия:

$(document).mousedown(function(){
  if ($(event.target).attr("id") == "mySpan") {
    // some process
  }
});
Евгений Шманев
источник
8

FocusEventЭкземпляры типа имеют relatedTargetатрибут, однако, до версии 47 FF, в частности, этот атрибут возвращает ноль, из 48 уже работает.

Вы можете увидеть больше здесь .

rplaurindo
источник
2

Я также пытаюсь заставить Autocompleter игнорировать размытие, если щелкнул конкретный элемент и у него есть рабочее решение, но только для Firefox из-за явногоOriginalTarget

Autocompleter.Base.prototype.onBlur = Autocompleter.Base.prototype.onBlur.wrap( 
        function(origfunc, ev) {
            if ($(this.options.ignoreBlurEventElement)) {
                var newTargetElement = (ev.explicitOriginalTarget.nodeType == 3 ? ev.explicitOriginalTarget.parentNode : ev.explicitOriginalTarget);
                if (!newTargetElement.descendantOf($(this.options.ignoreBlurEventElement))) {
                    return origfunc(ev);
                }
            }
        }
    );

Этот код оборачивает метод onBlur по умолчанию для Autocompleter и проверяет, установлены ли параметры ignoreBlurEventElement. если он установлен, он каждый раз проверяет, является ли нажатый элемент ignoreBlurEventElement или нет. Если это так, Autocompleter не вызывает onBlur, иначе он вызывает onBlur. Единственная проблема с этим заключается в том, что он работает только в Firefox, потому что свойство visibleOriginalTarget является специфическим для Mozilla. Теперь я пытаюсь найти другой способ, чем использовать явныйOriginalTarget. Решение, которое вы упомянули, требует, чтобы вы добавили поведение onclick вручную к элементу. Если мне не удастся решить проблему явного ориджинала, думаю, я последую вашему решению.

штейн
источник
2

Можете ли вы изменить то, что вы проверяете и когда? Вот если вы помните, что было размыто последним:

<input id="myInput" onblur="lastBlurred=this;"></input>

и затем в onClick для вашего диапазона вызовите функцию () с обоими объектами:

<span id="mySpan" onClick="function(lastBlurred, this);">Hello World</span>

Ваша функция может затем решить, следует ли запускать элемент управления Ajax.AutoCompleter. Функция имеет объект, по которому щелкнули, и размытый объект. OnBlur уже произошел, поэтому предложения не исчезнут.

BMB
источник
1

Используйте что-то вроде этого:

var myVar = null;

И тогда внутри вашей функции:

myVar = fldID;

А потом:

setTimeout(setFocus,1000)

А потом:

function setFocus(){ document.getElementById(fldID).focus(); }

Финальный код:

<html>
<head>
    <script type="text/javascript">
        function somefunction(){
            var myVar = null;

            myVar = document.getElementById('myInput');

            if(myVar.value=='')
                setTimeout(setFocusOnJobTitle,1000);
            else
                myVar.value='Success';
        }
        function setFocusOnJobTitle(){
            document.getElementById('myInput').focus();
        }
    </script>
</head>
<body>
<label id="jobTitleId" for="myInput">Job Title</label>
<input id="myInput" onblur="somefunction();"></input>
</body>
</html>
Викас
источник
1

Я думаю, что это невозможно, с IE вы можете попробовать использовать window.event.toElement, но это не работает с Firefox!

Стефано м
источник
Не работает с Chrome или Safari. Возможно, не будет работать с новыми версиями IE, которые более совместимы со стандартами.
Робокат
1

Как отмечено в этом ответе , вы можете проверить значение document.activeElement. documentэто глобальная переменная, поэтому вам не нужно предпринимать никаких действий, чтобы использовать ее в вашем обработчике onBlur:

function myOnBlur(e) {
  if(document.activeElement ===
       document.getElementById('elementToCheckForFocus')) {
    // Focus went where we expected!
    // ...
  }
}
Kevin
источник
1
  • document.activeElement может быть родительским узлом (например, узел тела, потому что он находится во временной фазе переключения с цели на другую), поэтому он не может использоваться для вашей области видимости
  • ev.explicitOriginalTarget не всегда оценивается

Поэтому лучше всего использовать onclick для события body для косвенного понимания того, что ваш узел (event.target) находится в размытом состоянии.


источник
1

Работает в Google Chrome v66.x, Mozilla v59.x и Microsoft Edge ... Решение с помощью jQuery.

Я тестирую в Internet Explorer 9 и не поддерживается.

$("#YourElement").blur(function(e){
     var InputTarget =  $(e.relatedTarget).attr("id"); // GET ID Element
     console.log(InputTarget);
     if(target == "YourId") { // If you want validate or make a action to specfic element
          ... // your code
     }
});

Прокомментируйте свой тест в других версиях Internet Explorer.

LuisEduardox
источник
0

Редактировать: хакерский способ сделать это - создать переменную, которая отслеживает фокусировку для каждого элемента, который вас интересует. Так что, если вам важно, чтобы myInput потерял фокус, установите для него переменную focus.

<script type="text/javascript">
   var lastFocusedElement;
</script>
<input id="myInput" onFocus="lastFocusedElement=this;" />

Оригинальный ответ: Вы можете передать «это» функции.

<input id="myInput" onblur="function(this){
   var theId = this.id; // will be 'myInput'
}" />
brock.holum
источник
это не отвечает на вопрос, надеюсь, я пояснил это на дополнительном примере
Michiel Borkent,
0

Я предлагаю использовать глобальные переменные blurfrom и blurto. Затем настройте все элементы, которые вам нужны, чтобы назначить их положение в DOM для переменной blurfrom, когда они теряют фокус. Кроме того, сконфигурируйте их так, чтобы при получении фокуса переменная blurto заняла их положение в DOM. Затем вы можете использовать другую функцию для анализа данных размытия и размытия.

stalepretzel
источник
Это почти решение, но в обработчике событий onblur мне уже нужно было знать, по какому элементу щелкнули, поэтому тайм-аут на onblur сделал это для меня.
Михил Боркент
0

имейте в виду, что решение с явнымOriginalTarget не работает для переходов ввода текста в ввод текста.

Попробуйте заменить кнопки следующими текстовыми вводами, и вы увидите разницу:

<input id="btn1" onblur="showBlur(event)" value="text1">
<input id="btn2" onblur="showBlur(event)" value="text2">
<input id="btn3" onblur="showBlur(event)" value="text3">

источник
0

Я играл с этой же функцией и обнаружил, что FF, IE, Chrome и Opera имеют возможность предоставлять исходный элемент события. Я не тестировал Safari, но думаю, что он может иметь что-то похожее.

$('#Form').keyup(function (e) {
    var ctrl = null;
    if (e.originalEvent.explicitOriginalTarget) { // FF
        ctrl = e.originalEvent.explicitOriginalTarget;
    }
    else if (e.originalEvent.srcElement) { // IE, Chrome and Opera
        ctrl = e.originalEvent.srcElement;
    }
    //...
});
EricDuWeb
источник
это прекрасно работает, почему downvoting? просто удалите originalEvent!
фекири малек
0

Мне не нравится использовать тайм-аут при кодировании javascript, поэтому я бы сделал это противоположным образом, как Михил Боркент. (Не пробовал код, но вы должны понять).

<input id="myInput" onblur="blured = this.id;"></input>
<span onfocus = "sortOfCallback(this.id)" id="mySpan">Hello World</span>

В голове что-то подобное

<head>
    <script type="text/javascript">
        function sortOfCallback(id){
            bluredElement = document.getElementById(blured);
            // Do whatever you want on the blured element with the id of the focus element


        }

    </script>
</head>
Ронан Киллевер
источник
0

Вы можете исправить IE с помощью:

 event.currentTarget.firstChild.ownerDocument.activeElement

Похоже, что "visibleOriginalTarget" для FF.

Антуан И Дж

Madbean
источник
0

Я написал альтернативное решение, как сделать любой элемент фокусируемым и «слепым».

Он основан на создании элемента как contentEditableи скрытии его визуально и отключении самого режима редактирования:

el.addEventListener("keydown", function(e) {
  e.preventDefault();
  e.stopPropagation();
});

el.addEventListener("blur", cbBlur);
el.contentEditable = true;

DEMO

Примечание. Протестировано в Chrome, Firefox и Safari (OS X). Не уверен насчет IE.


Связанный: я искал решение для VueJ, поэтому для тех, кому интересно / интересно, как реализовать такую ​​функциональность с помощью директивы Vue Focusable, пожалуйста, посмотрите .

Сергей Матрунчик
источник
-2

Сюда:

<script type="text/javascript">
    function yourFunction(element) {
        alert(element);
    }
</script>
<input id="myinput" onblur="yourFunction(this)">

Или, если вы присоединяете слушателя через JavaScript (jQuery в этом примере):

var input = $('#myinput').blur(function() {
    alert(this);
});

Изменить : извините. Я неправильно понял вопрос.

Армин Ронахер
источник
3
Если вам известно, что это не ответ на вопрос, и вы неправильно его прочитали, пожалуйста, обновите его или удалите.
TJ
-2


Я думаю, что это легко возможно через jquery, передавая ссылку на поле, вызывающее событие onblur в «this».
Например,

<input type="text" id="text1" onblur="showMessageOnOnblur(this)">

function showMessageOnOnblur(field){
    alert($(field).attr("id"));
}

Спасибо
моника

Моника Шарма
источник
-2

Вы можете сделать это так:

<script type="text/javascript">
function myFunction(thisElement) 
{
    document.getElementByName(thisElement)[0];
}
</script>
<input type="text" name="txtInput1" onBlur="myFunction(this.name)"/>
Шикекака Ямирюкидо
источник
-2

Я вижу только хаки в ответах, но на самом деле есть встроенное решение, очень простое в использовании: в основном вы можете захватить элемент фокуса следующим образом:

const focusedElement = document.activeElement

https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement

Томас Дж.
источник
По крайней мере, в моем случае это не работает, так как activeElement - это тело, если я проверяю это на следующем рендере / тике, он установлен правильно. Но кажется, что решение shog9 - единственное правильное решение, так как оно гарантирует, что галочка будет работать.
Матийс Сегерс