Bootstrap 5.2, предотвращает закрытие всплывающей подсказки, если курсор снова находится на элементе запуска

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).

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

в вашем коде у вас есть прослушиватель событий, который добавляет список событий, и это большая ошибка, потому что он добавляет к вашему элементу бесконечное число событий.

поэтому вам просто нужно организовать свой код следующим образом:

//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 секунды, прежде чем проверять, скрыто ли всплывающее окно или нет.

Я действительно нашел проблему с кодом. После закрытия всплывающей подсказки она больше не открывается. Я получаю сообщение об ошибке currentToolTip is null в блоке try catch. Посмотреть проблему можно здесь jsfiddle.net/v4au9tsm/3

WeAreDoomed 16.12.2022 18:13

Я сузил его до aria-describedby, так как второй раз он не генерируется

WeAreDoomed 16.12.2022 18:34

я проверил ваш код на jsfiddle.net/v4au9tsm/3 => вы не можете вкладывать события, вот и все, я вам уже объяснил.

Amine Ramoul 17.12.2022 18:26

для ошибки, которую вы упомянули в предыдущем комментарии, ошибка возникает из-за того, что вы переместили объявление if isHidden в событие, поэтому второе событие не может получить доступ к этой переменной, и вы получили ошибку

Amine Ramoul 17.12.2022 18:28

вы можете проверить исправление jsfiddle.net/v4au9tsm/3 здесь jsfiddle.net/yf30cxnh

Amine Ramoul 17.12.2022 18:37

Другие вопросы по теме