简体   繁体   中英

Find previous element of same type regardless of parent

I would like to be able to find the previous element of a certain type, whether it is contained within the same parent or not.

In this situation I want to find the previous input[type="text"] element and give it focus.

Currently I can select the previous sibling in the same parent, but would like to be able to filter that to only input[type="text"] elements and allow the previous parent as well.

The accepted answer will be vanilla javascript only.

 document.addEventListener('keydown', function(e) { // if backspace is pressed and the input is empty if (e.keyCode === 8 && e.target.value.length === 0) { // This should give focus to the previous input element e.target.previousSibling.previousSibling.focus(); } }, false); 
 <div> <input type="text"> <input type="text"> </div> <div> <input type="text"> <input type="text"> </div> <div> <input type="text"> <input type="text"> </div> 

You could just use querySelectorAll to get all matching elements and then loop to find the one you are in, then focus the previous. The result of querySelectorAll is in "document order".

 document.addEventListener('keydown', function(e) { if (e.keyCode === 8 && e.target.value.length === 0) { // This should give focus to the previous input element var inputs = document.querySelectorAll('input[type="text"]'); for(var i = 1; i < inputs.length; i++){ if(inputs[i] == e.target){ inputs[i-1].focus(); break; } } } }, false); 
 <div> <input type="text"> <input type="text"> </div> <div> <input type="text"> <input type="text"> </div> <div> <input type="text"> <input type="text"> </div> 

Instead of listening to all events occurring on the document, looking for events triggered on certain elements, you can use the following method.

Select and cache the scope element which contains the elements you want to cycle through.

Select and cache all of the elements you want to cycle through from the scope we selected previously in a list.

Loop through all of the elements in the list, in each iteration of the loop:

  1. Use an Immediately Invoked Function Expression (IIFE) to create a new lexical scope where you can store the index associated with the current element in that scope.
  2. Assign an event listener to the 'keydown' event for that element where you check to see if the backspace key was pressed and the field is empty; if these checks pass either:
    • set the focus on the previous element in the list of elements previously selected;
    • or, if the current element is the first element in the list, set the focus on the last element in the list.

Using this method:

  • you only query the DOM twice (in a limited scope),
  • you aren't listening to every keydown event fired on every element in the entire document, and
  • you can cycle infinitely by looping from the beginning to the end.

 var scope = document.querySelector('.scope'); var inputs = scope.querySelectorAll('input[type="text"]'); for (var i in Object.keys(inputs)) (function(index){ inputs[i].addEventListener('keydown', function(e){ if (e.which === 8 && this.value.length === 0) { var next = index - 1; if (next < 0) next = inputs.length - 1; inputs[next].focus(); } }, false); })(i); 
 <div class="scope"> <div><input type="text"><input type="text"></div> <div><input type="text"><input type="text"></div> <div><input type="text"><input type="text"></div> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM