TLDR: перемещение курсора от всплывающей подсказки обратно к активирующему элементу закрывает, показывает и закрывает всплывающую подсказку (мерцает).
Мне нужно, чтобы всплывающие подсказки открывались при наведении и делали их содержимое кликабельным. Я нашел рабочий пример здесь на SO.
Когда вы наводите курсор на элемент, он показывает вам всплывающую подсказку, с которой можно взаимодействовать, как только вы отводите курсор от всплывающей подсказки, она закрывается.
Однако есть проблема.
Если вы покинете всплывающую подсказку и переместите курсор обратно на элемент, который вызвал всплывающую подсказку, всплывающая подсказка снова появится, но через мгновение исчезнет («мерцает»). Вам нужно переместить курсор от элемента и вернуться к элементу, чтобы всплывающая подсказка снова отобразилась.
Что я пытаюсь сделать, так это проверить, вернулся ли курсор к элементу запуска, и если это так, не запускайте функцию закрытия (tooltip.hide()
).
Я попытался сделать это, имитируя существующий процесс из примера, найденного на SO. То есть проверьте, не потеряла ли всплывающая подсказка :hover
, setTimout
(300 мс), и проверьте, находится ли курсор сейчас на элементе запуска или обратно на всплывающей подсказке.
Вот пример jsFiddle.
Это код. Проблемный код находится между двумя длинными строками комментариев.
Примечание. Перемещение курсора от элемента запуска и обратно к элементу запуска также вызывает мерцание.
//https://stackoverflow.com/questions/67993080/bootstrap-5-make-tooltip-hoverable-and-link-clickable
var tooltipTriggerList = [].slice.call(document.querySelectorAll('button'))
for (let tt of tooltipTriggerList){
tt.setAttribute("data-bs-placement","top")
}
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
const tooltip = new bootstrap.Tooltip(tooltipTriggerEl, {
trigger: "manual",
'customClass': 'custom-tooltip'
})
let tooltipElTimeout;
let currentToolTip;
let currentTooltipTimeout;
tooltipTriggerEl.addEventListener("mouseenter", function () {
let toolTipID;
// Clear Set Timeout
clearTimeout(currentTooltipTimeout);
// Show Tooltip
tooltip.show();
// Assign current tooltip ID to toolTipID variable
toolTipID = tooltipTriggerEl.getAttribute("aria-describedby");
// Assign current tooltip to currentToolTip variable
currentToolTip = document.querySelector(`#${toolTipID}`);
/*******************************************************************/
// Hide tooltip on tooltip mouse leave
currentToolTip.addEventListener("mouseleave", function () {
currentTooltipTimeout = setTimeout(()=>{
console.info("!currentToolTip.matches(':hover')");
console.info(!currentToolTip.matches(":hover"));
if (!tooltipTriggerEl.matches(":hover")){
console.info("!tooltipTriggerEl.matches(':hover')");
console.info(!tooltipTriggerEl.matches(":hover"));
if (!currentToolTip.matches(":hover")) {
tooltip.hide();
}
}
}, 300)
});
/***********************************************************************/
});
tooltipTriggerEl.addEventListener("mouseleave", function () {
// SetTimeout before tooltip disappears
tooltipTimeout = setTimeout(function () {
// Hide tooltip if not hovered.
if (!currentToolTip.matches(":hover")) {
tooltip.hide();
}
}, 100);
});
return tooltip;
})
Спасибо
Редактировать:
Ответ Амине Рамульс правильный. isHidden
также необходимо установить значение false для 2cnd eventListener, иначе всплывающие подсказки больше не работают (проблема с aria-describedby
).
в вашем коде у вас есть прослушиватель событий, который добавляет список событий, и это большая ошибка, потому что он добавляет к вашему элементу бесконечное число событий.
поэтому вам просто нужно организовать свой код следующим образом:
//https://stackoverflow.com/questions/67993080/bootstrap-5-make-tooltip-hoverable-and-link-clickable
var tooltipTriggerList = [].slice.call(document.querySelectorAll('button'))
for (let tt of tooltipTriggerList){
tt.setAttribute("data-bs-placement","top")
}
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
const tooltip = new bootstrap.Tooltip(tooltipTriggerEl, {
trigger: "manual",
'customClass': 'custom-tooltip'
})
let isHidden = true;
let currentTooltipTimeout;
tooltipTriggerEl.addEventListener("mouseenter", function () {
let toolTipID;
// Clear Set Timeout
clearTimeout(tooltipElTimeout);
clearTimeout(currentTooltipTimeout);
if (isHidden)
{
tooltip.show();
isHidden=false;
}
});
// Hide tooltip on tooltip mouse leave
tooltipTriggerEl.addEventListener("mouseleave", function () {
console.info("!currentToolTip.matches(':hover')");
if (!tooltipTriggerEl.matches(":hover")){
currentTooltipTimeout=setTimeout(()=>{
if (!isHidden && !tooltipTriggerEl.matches(":hover")){
tooltip.hide();
isHidden=true;
}
console.info("!tooltipTriggerEl.matches(':hover')");
console.info(!tooltipTriggerEl.matches(":hover"));
}, 3000)
}
});
return tooltip;
})
теперь, как вы можете видеть, я только что добавил isHidden var, чтобы проверить, скрыта ли всплывающая информация или нет, вы можете сделать это с элементом, если вы можете получить его с помощью запроса селектора запроса. вот и все. Наслаждайся своей жизнью.
Редактировать: я забыл сказать вам, что я поставил 3 секунды, прежде чем проверять, скрыто ли всплывающее окно или нет.
Я сузил его до aria-describedby
, так как второй раз он не генерируется
я проверил ваш код на jsfiddle.net/v4au9tsm/3 => вы не можете вкладывать события, вот и все, я вам уже объяснил.
для ошибки, которую вы упомянули в предыдущем комментарии, ошибка возникает из-за того, что вы переместили объявление if isHidden в событие, поэтому второе событие не может получить доступ к этой переменной, и вы получили ошибку
вы можете проверить исправление jsfiddle.net/v4au9tsm/3 здесь jsfiddle.net/yf30cxnh
Я действительно нашел проблему с кодом. После закрытия всплывающей подсказки она больше не открывается. Я получаю сообщение об ошибке
currentToolTip is null
в блоке try catch. Посмотреть проблему можно здесь jsfiddle.net/v4au9tsm/3