Ниже приведена упрощенная версия раскрывающегося списка ввода, с которым я работаю.
Основная сводка того, что он делает: если вы сосредоточитесь на вводе, появится выпадающий список. Если щелкнуть один из параметров в раскрывающемся списке, этот параметр заполняет ввод, и раскрывающийся список исчезает. Это достигается с помощью onfocus
и функций, которые я назвал dropdown();
и undropdown();
.
У меня дилемма, когда я не могу заставить раскрывающийся список исчезнуть, когда кто-то щелкает в другом месте. Если я использую onblur
, он успешно скрывает раскрывающийся список, но если вы нажимаете на опцию, он не заполняет ввод, это потому, что сначала запускается функция onblur
и, следовательно, {{ X2}} функция не запускается, потому что раскрывающийся список уже скрыт.
Если вы поместите onclick
в тег body или другого родителя, он будет рассматривать onfocus
как щелчок, где он запускает функцию dropdown();
, а затем функцию undropdown();
сразу раскрывающийся список никогда не появляется, поскольку функции перекрываются.
Я был бы признателен за помощь в выяснении, как упорядочить функции так, чтобы они выполнялись в правильном порядке, не перекрывая друг друга.
JSFiddle доступен здесь.
function input(pos) {
var dropdown = document.getElementsByClassName('drop');
var li = dropdown[0].getElementsByTagName("li");
document.getElementsByTagName('input')[0].value = li[pos].innerHTML;
undropdown(0);
}
function dropdown(pos) {
document.getElementsByClassName('content')[pos].style.display = "block"
}
function undropdown(pos) {
document.getElementsByClassName('content')[pos].style.display = "none";
}
.drop {
position: relative;
display: inline-block;
vertical-align: top;
overflow: visible;
}
.content {
display: none;
list-style-type: none;
border: 1px solid #000;
padding: 0;
margin: 0;
position: absolute;
z-index: 2;
width: 100%;
max-height: 190px;
overflow-y: scroll;
}
.content li {
padding: 12px 16px;
display: block;
margin: 0;
}
<div class="drop">
<input type="text" name="class" placeholder="Class" onfocus="dropdown(0)"/>
<ul class="content">
<li onclick="input(0)">Option 1</li>
<li onclick="input(1)">Option 2</li>
<li onclick="input(2)">Option 3</li>
<li onclick="input(3)">Option 4</li>
</ul>
</div>
PS: В дополнение к вышеупомянутой проблеме, я был бы признателен за внесение изменений, чтобы получить лучший заголовок для этого вопроса, чтобы кто-нибудь, столкнувшийся с подобной проблемой, мог найти его более легко.
3 ответа
В этом случае On onblur
вы можете вызвать функцию, которая запускает undropdown(0);
после очень маленького setTimeout почти мгновенно. Вот так:
function set() {
setTimeout(function(){
undropdown(0);
}, 100);
}
< Сильный > HTML
<input type="text" name="class" placeholder="Class" onfocus="dropdown(0)" onblur="set()" />
Никаких других изменений не требуется.
function input(pos) {
var dropdown = document.getElementsByClassName('drop');
var li = dropdown[0].getElementsByTagName("li");
document.getElementsByTagName('input')[0].value = li[pos].innerHTML;
undropdown(0);
}
function dropdown(pos) {
document.getElementsByClassName('content')[pos].style.display= "block"
}
function undropdown(pos) {
document.getElementsByClassName('content')[pos].style.display= "none";
}
function set() {
setTimeout(function(){
undropdown(0);
}, 100);
}
.drop {
position: relative;
display: inline-block;
vertical-align:top;
overflow: visible;
}
.content {
display: none;
list-style-type: none;
border: 1px solid #000;
padding: 0;
margin: 0;
position: absolute;
z-index: 2;
width: 100%;
max-height: 190px;
overflow-y: scroll;
}
.content li {
padding: 12px 16px;
display: block;
margin: 0;
}
<div class="drop">
<input type="text" name="class" placeholder="Class" onfocus="dropdown(0)" onblur="set()" />
<ul class="content">
<li onclick="input(0)">Option 1</li>
<li onclick="input(1)">Option 2</li>
<li onclick="input(2)">Option 3</li>
<li onclick="input(3)">Option 4</li>
</ul>
</div>
Принятый ответ - наивный и ненадежный подход. У меня была сложная ошибка в сложном приложении, потому что я использовал setTimeout
для задержки ~ 200 мс, чтобы браузер мог обработать выпадающий щелчок, прежде чем произойдет событие размытия. Хотя он отлично работал на каждой установке, с которой я тестировал, некоторые пользователи имели проблемы, в частности, пользователи с более медленными машинами.
Правильный способ - проверить relatedTarget
на событии focusout
:
input.addEventListener('focusout', function(event) {
if(!isDropdownElement(event.relatedTarget)) {
// hide dropdown
}
});
relatedTarget
для focusout
содержит элемент элемент ссылка, которая получает фокус. Это надежно работает во всех протестированных мною браузерах (я не тестировал IE10 и ниже, только IE11 и Edge).
Вы можете сделать раскрывающийся список фокусируемым с помощью tabindex
, а в обработчике событий blur
входного параметра скрыть раскрывающийся список, только если фокус не перешел на раскрывающийся список (см. Когда происходит onblur, как я могу узнать, какой фокус элемента перешел на ? )
<ul class="content" tabindex="-1"></ul>
input.addEventListener('blur', function(e) {
if(!e.relatedTarget || !e.relatedTarget.classList.contains('content')) {
undropdown(0);
}
});
function input(e) {
var dropdown = document.getElementsByClassName('drop');
var li = dropdown[0].getElementsByTagName("li");
document.getElementsByTagName('input')[0].value = e.target.textContent;
undropdown(0);
}
[].forEach.call(document.getElementsByTagName('li'), function(el) {
el.addEventListener('click', input);
});
function dropdown(pos) {
document.getElementsByClassName('content')[pos].style.display = "block"
}
function undropdown(pos) {
document.getElementsByClassName('content')[pos].style.display = "none";
}
var input = document.getElementsByTagName('input')[0];
input.addEventListener('focus', function(e) {
dropdown(0);
});
input.addEventListener('blur', function(e) {
if(!e.relatedTarget || !e.relatedTarget.classList.contains('content')) {
undropdown(0);
}
});
.drop {
position: relative;
display: inline-block;
vertical-align: top;
overflow: visible;
}
.content {
display: none;
list-style-type: none;
border: 1px solid #000;
padding: 0;
margin: 0;
position: absolute;
z-index: 2;
width: 100%;
max-height: 190px;
overflow-y: scroll;
outline: none;
}
.content li {
padding: 12px 16px;
display: block;
margin: 0;
}
<div class="drop">
<input type="text" name="class" placeholder="Class" />
<ul class="content" tabindex="-1">
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
<li>Option 4</li>
</ul>
</div>
Похожие вопросы
Связанные вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.