У меня есть три кнопки всплывающей подсказки на странице. Я могу закрыть любую открытую подсказку, нажимая в любом месте за пределами кнопок. И вот что я наткнулся:
В приведенном ниже коде, когда я нажимаю на любое место на странице, активируется обработчик этой части кода $(document).on('click', (event) => this.closeOnOutsideClick(event));
Я вижу в инспекторе, что функция closeOnOutsideClick
запускается три раза - она делает три проверки для каждой кнопки всплывающей подсказки, присутствующей на странице. Я не могу понять, какой механизм отвечает за это и почему проверка if (!$(event.target).closest(this.$elem))
не выполняется только один раз? Мой код можно найти здесь, а также ниже: https://jsfiddle.net/bakrall/786cz40L/
Это упрощенная версия более сложного кода, чтобы привести пример моей проблемы:
const selectors = {
tooltip: '.tooltip-container',
tooltipButton: '.tooltip-button',
tooltipMessage: '.tooltip-message'
}
class Tooltip {
constructor(tooltip) {
this.$elem = $(tooltip);
this.$tooltipButton = this.$elem.find(selectors.tooltipButton);
this.$tooltipMessage = this.$elem.find(selectors.tooltipMessage);
this.$tooltipMessageText = this.$tooltipButton.attr('data-tooltip-content');
this.bindUiEvents();
}
bindUiEvents() {
$(document).on('click', (event) => this.closeOnOutsideClick(event));
this.$tooltipButton.on('click', () => this.showTooltipMessage());
this.$tooltipButton.on('blur', () => this.hideTooltip());
}
showTooltipMessage() {
this.$tooltipMessage
.text(this.$tooltipMessageText)
.addClass('shown-message');
}
hideTooltip() {
this.$tooltipMessage
.text('')
.removeClass('shown-message');
}
closeOnOutsideClick(event) {
if (!$(event.target).closest(this.$elem)) {
this.hideTooltip();
}
}
}
//class in another file
const tooltip = $('.tooltip-container');
tooltip.each(function(index, item) {
new Tooltip(item);
})
.input-wrapper {
margin-bottom: 2em;
}
.tooltip-container {
position: relative;
display: inline-block;
}
.tooltip-message {
display: none;
position: absolute;
left: 100%;
top: 0;
width: 10em;
padding: 0.5rem;
background: #000;
color: #fff;
}
.tooltip-message.shown-message {
display: inline-block;
}
button {
width: 1.2em;
height: 1.2em;
border-radius: 50%;
border: 0;
background: #000;
font-family: serif;
font-weight: bold;
color: #fff;
}
button:focus {
outline: none;
box-shadow: 0 0 0 0.25rem skyBlue;
}
input {
display: block;
}
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title> </title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="tooltip.css">
</head>
<body>
<div class="input-wrapper">
<label for="name">
What's your name?
<span class="tooltip-container">
<button class="tooltip-button" type="button" aria-label="more info"
data-tooltip-content="This clarifies whatever needs clarifying">i</button>
<span class="tooltip-message" role="status"></span>
</span>
</label>
<input id="name" type="text"/>
</div>
<div class="input-wrapper">
<label for="age">
What's your age?
<span class="tooltip-container">
<button class="tooltip-button" type="button" aria-label="more info"
data-tooltip-content="This is to know how old you are">i</button>
<span class="tooltip-message" role="status"></span>
</span>
</label>
<input id="age" type="text"/>
</div>
<div class="input-wrapper">
<label for="nationality">
What's your nationality
<span class="tooltip-container">
<button class="tooltip-button" type="button" aria-label="more info"
data-tooltip-content="What country are you from?">i</button>
<span class="tooltip-message" role="status"></span>
</span>
</label>
<input id="nationality" type="text"/>
</div>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous">
</script>
<script src="tooltip.js" async defer></script>
</body>
</html>
2 ответа
tooltip.each(function(index, item) {
new Tooltip(item);
})
Поскольку вы создаете 3 подсказки, вы каждый раз привязываете отдельный прослушиватель событий к документу. Каждый слушатель срабатывает при каждом нажатии. Однако у каждого из этих слушателей есть свой this
, который позволяет каждому слушателю сказать, была ли нажата его подсказка, и если нет, скрыть его.
Если вам нужен единственный прослушиватель, вы можете сохранить список всех ваших подсказок и сделать так, чтобы прослушиватель событий перебирал список подсказок, закрывая все подсказки, которые не были нажаты.
Ваше событие нажатия срабатывает на нескольких элементах, потому что вы указали только (документ). Может быть, вы можете быть более конкретным:
$(document).on('click', '.input-wrapper', (event) => this.closeOnOutsideClick(event));
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript/JS) и его различных диалектах/реализациях (кроме ActionScript). Обратите внимание, что JavaScript — это НЕ Java. Включите все теги, относящиеся к вашему вопросу: например, [node.js], [jQuery], [JSON], [ReactJS], [angular], [ember.js], [vue.js], [typescript], [стройный] и т. д.