Коли трапляється подія "розмивання", як я можу дізнатися, на який фокус елемента пішов * до *?


187

Припустимо, я додаю blurфункцію до вікна введення HTML таким чином:

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

Чи є спосіб отримати ідентифікатор елемента, який спричинив загору blurподії (елемент, який було натиснуто) всередині функції? Як?

Наприклад, припустимо, у мене такий проміжок:

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

Якщо я натискаю на проміжок відразу після того, як елемент введення фокусується, вхідний елемент втратить фокус. Звідки функція знає, що її mySpanнатиснули?

PS: Якщо подія onclick span відбудеться до події onblur вхідного елемента, моя проблема буде вирішена, тому що я можу встановити якесь значення стану, що вказує на певний елемент, який було натиснуто.

PPS: Основою цієї проблеми є те, що я хочу запустити керування автокомплектором AJAX зовні (з елемента, який можна натиснути), щоб показати його пропозиції, без пропозицій одразу зникати через blurподію на вхідному елементі. Тому я хочу перевірити blurфункцію, чи натиснули один конкретний елемент, і якщо так, ігноруйте подію розмиття.


Це цікаве питання, на яке я хотів би бачити міркування - тобто чому ти це робиш? Що таке контекст?
Рахул

Рахуль і ростеронацид, я оновив питання як реакцію на ваші коментарі (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" />

Caveat: Ця методика не працює для змін фокусу, викликаних вкладками через поля з клавіатурою, і зовсім не працює в Chrome або Safari. Велика проблема з використанням activeElement( за винятком IE) є те , що вона не постійно оновлюється до тих пір , післяblur того, як подія було оброблено, і може не мати дійсне значення взагалі при обробці! Це можна пом'якшити за допомогою варіації техніки Michiel, в результаті якої використовуються :

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 не встановлює фокус на кнопки, які натискаються (порівняно з вкладками).


1
Я довго шукав щось на зразок явногоOriginalTarget. Як ви це відкрили?
Кев

3
Оглянув об’єкт події в FireBug. FWIW, властивість призначена для Mozilla та задокументована на MDC: developer.mozilla.org/uk/DOM/event.explicitOriginalTarget
Shog9,

2
Це не працює (або перестало працювати?) У Firefox 3.6 та Safari 4.0.3 у Windows.
Chetan S

1
@Jonathan: властивість доступна, але не оновлюється, коли blurподія запускається. Я оновив відповідь деталями. Ви намагалися використовувати для цього ActiveElement у Chrome чи Firefox? Це дає вам стихію
розмитись

1
Насправді не працює на FF 31: expressOriginalTarget показує поточну ціль розмиття, document.activeElement є нульовою для події розмиття.
Адріан Мюр

75

Відповідь 2015 року : згідно з подіями UI , ви можете використовувати relatedTargetвластивість події:

Використовується для ідентифікації вторинного, EventTargetпов’язаного з подією фокусування, залежно від типу події.

Для 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

3
Тепер це є. Дивіться тут .
rplaurindo

люблю веб-спільноту, зараз все набагато простіше ^ _ ^
am05mhz

6
Прекрасне рішення. На жаль, relatedTargetповернеться, nullякщо цільовий фокус прийому не є вхідним елементом.
Pedro Hoehl Carvalho

5
Якщо отримання фокусного елемента не є вхідним елементом, додайте 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 btw?
Міхель Боркент,

1
стара посада, але у мене те саме питання. незважаючи на це, це єдине, що, здається, робить роботу крос-браузером.
Джош

ця відповідь допомогла моєму ТОН, вирішивши якусь іншу проблему ... Дякую Майклу!
Олексій

@MichielBorkent це погана реалізація, оскільки це не спричинено подіями. Ви чекаєте заданої кількості часу і просто сподіваєтесь, що пройшло досить довго. Чим довше ви будете чекати, тим безпечніше ви будете, але і тим більше часу будете витрачати, якщо вам не потрібно було чекати так довго. Можливо, хтось на справді старому / повільному пристрої, і цього тайм-ауту недостатньо. На жаль, я тут, тому що події не дають мені того, що потрібно визначити, чи натискається на iframe у FireFox, але він працює для всіх інших браузерів. Мені дуже сподобалося зараз використовувати цей метод, хоча це погана практика.
CTS_AE

1
Це питання досить старе, воно починається з 2008 року. Тим часом, можливо, були кращі підходи. Чи можете ви спробувати відповідь 2015 року?
Міхель Боркент

16

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

$(document).mousedown(function(){
  if ($(event.target).attr("id") == "mySpan") {
    // some process
  }
});

8

Типи FocusEventекземплярів мають relatedTargetатрибут, однак, до версії 47 FF, зокрема, цей атрибут повертає нуль, з 48 вже працює.

Більше ви можете побачити тут .


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 за замовчуванням автозаповнення та перевіряє, чи встановлено параметри ignoreBlurEventElement. якщо він встановлений, він перевіряє щоразу, чи клацнув елемент ігноруєтьсяBlurEventElement чи ні. Якщо це так, Autocompleter не називає onBlur, інакше він викликає onBlur. Єдина проблема з цим полягає в тому, що він працює лише у Firefox, оскільки властивість expressOriginalTarget є специфічною для Mozilla. Зараз я намагаюся знайти інший спосіб, ніж використання явногоOriginalTarget. Ви згадане рішення вимагає, щоб ви вручну додали елемент поведінки onclick. Якщо я не в змозі вирішити проблему явногоOriginalTarget, я думаю, я буду виконувати ваше рішення.


2

Чи можете ви змінити те, що ви перевіряєте, і коли? Тобто якщо ви пам’ятаєте те, що було розмито останнім:

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

а потім у onClick для вашого інтервалу виклик функції () з обома об'єктами:

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

Тоді ваша функція може вирішити, чи слід запускати керування Ajax.AutoCompleter. Функція має об'єкт, що клацнув, і об'єкт "Розмитий". OnBlur вже відбувся, тому пропозиції не зникнуть.


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, суміснішими за більшістю стандартів.
robocat

1

Як зазначено у цій відповіді , ви можете перевірити значення document.activeElement. documentє глобальною змінною, тому вам не потрібно робити ніякої магії, щоб використовувати її у своєму обробці onBlur:

function myOnBlur(e) {
  if(document.activeElement ===
       document.getElementById('elementToCheckForFocus')) {
    // Focus went where we expected!
    // ...
  }
}

1
  • document.activeElement може бути батьківським вузлом (наприклад, вузол тіла, оскільки він перебуває у тимчасовій фазі, перемикаючись з цільової на іншу), тому він не може бути використаний для вашої області
  • ev.explicitOriginalTarget не завжди цінується

Тож найкращий спосіб - використовувати onclick on body 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.


0

Редагувати: Хакітним способом це було б створити змінну, яка б відслідковувала фокус для кожного елемента, який вам цікавий. Отже, якщо вам все одно, що "myInput" втратив фокус, встановіть йому змінну на фокус.

<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'
}" />

це не відповідає на питання, сподіваюсь, я
зрозумів

0

Я пропоную використовувати глобальні змінні blurfrom та blurto. Потім налаштуйте всі елементи, які вам цікаві, щоб призначити їх положення в DOM змінній blurfrom, коли вони втрачають фокус. Крім того, налаштуйте їх так, щоб посилення фокусу встановлювало змінну blurto до їх положення в DOM. Тоді ви можете взагалі використовувати іншу функцію для аналізу даних blurfrom та blurto.


Це майже рішення, але в обробці подій onblur мені вже потрібно було знати, на який елемент було натиснуто, тому тайм-аут на onblur зробив це для мене.
Міхель Боркент,

0

майте на увазі, що рішення з expressOriginalTarget не працює для стрибків введення тексту в текст.

спробуйте замінити кнопки на наступні текстові введення, і ви побачите різницю:

<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;
    }
    //...
});

це добре працює, чому зволікаючи? просто видаліть originalEvent!
fekiri malek

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

Це виглядає як "явнийOriginalTarget" для FF.

Антуан і Дж


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.


Пов’язано. Я шукав рішення для VueJs, тому для тих, хто зацікавлений / цікавий, як реалізувати таку функціональність за допомогою директиви 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, в "це".
Наприклад, наприклад

<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 є єдиним правильним рішенням, оскільки воно гарантує, що галочка була начинена.
Mathijs Segers
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.