Проблемы с setTimeout / clearTimeout, похоже, не сбрасываются

0

Я пытаюсь создать меню, которые выпадают при наведении указателя на название меню. Поскольку имена и панели меню не смежны, мне нужен способ отсрочить исчезновение меню, чтобы пользователи могли перейти от имени к самому меню. Для этого я использовал setTimeout. Как только наведите курсор на меню, мне нужно, чтобы он оставался открытым до тех пор, пока не исчезнет мышь, после чего она должна скрыться.

То, что я пробовал, - полный беспорядок. Не знаете, как это исправить. Поскольку setTimeout находится внутри начальной мыши, таймер циклы над собой... но setTimeout, похоже, не работает, если я помещу его в другое место.

Здесь код:

$(document).ready(function() {
  $('.headermenushow').mouseover(function () {
    $(this).next('.dropmenu').show(0, function () {
      timer = setTimeout(function() {
        $('.dropmenu').hide(10);
      }, 2000);
    });

    $(this).next('.dropmenu').mouseover(function () {
      clearTimeout(timer);
    });

  });
});

Здесь сокращенный jsfiddle, показывающий, как я хочу его использовать:

http://jsfiddle.net/H247x/1/

Любая помощь будет большой. Не совсем уверен, как это лучше работает...

  • 4
    Можете ли вы предоставить нам jsfiddle для этого.
  • 0
    Нам нужно увидеть ваш HTML и лучше понять, что именно вы пытаетесь достичь. В нынешнем виде ясно, что с вашим текущим кодом не все в порядке, но не совсем понятно, что вы пытаетесь сделать.
Показать ещё 1 комментарий
Теги:
settimeout

1 ответ

5
Лучший ответ

С этим кодом возникают всевозможные проблемы:

  1. Вы добавляете обработчики событий внутри события .mouseover(). Это означает, что каждый раз, когда есть событие mouseover, вы добавляете еще один набор обработчиков событий. Они будут накапливаться и создавать реальный беспорядок, когда все исполнятся. Для каждого активного объекта нужен один и только один набор обработчиков событий.

  2. Вся ваша логика, как это должно работать, кажется ошибочной. Вы хотите, чтобы меню оставалось опущенным до тех пор, пока мышь над предметом. Событие mouseover происходит только тогда, когда мышь сначала перемещается на элемент. У вас нет способа сохранить меню, когда мышь наводится на него, поскольку вы просто слепо скрываете его через 2 секунды после показа, независимо от того, находится ли мышь там или нет.

  3. Вы используете неявную глобальную переменную для своего таймера. Это создает множество проблем. Во-первых, если есть более одного объекта .headermenushow, каждый timer объекта будет наступать на остальные. Во-вторых, неявные глобальные переменные просто плохи и могут легко привести к ошибкам. Объявите его неявно в области, в которой вы хотите.

  4. Вы можете использовать таймеры сверху таймеров. Каждый раз, когда вы сохраняете таймер для общей переменной, вы должны либо проверить предыдущий таймер, который уже запущен, либо остановить предыдущий таймер, прежде чем перезаписать его. Это предотвращает потерю следа запущенного таймера и предотвращает стекирование нескольких таймеров, все пытаются сделать то же самое.

Вероятно, мы могли бы помочь вам придумать гораздо лучший код, но нам нужно будет увидеть ваш фактический HTML и лучше понять, что именно такое поведение вы пытаетесь реализовать.

FYI, вы также можете просмотреть селектор CSS :hover, который позволит вам показывать/скрывать вещи при наведении курсора без какого-либо JS-кода вообще. Поскольку я не знаю, как выглядит ваш HTML, я не могу точно сказать, будет ли это работать для вас, но он используется многими системами меню, и это действительно просто, когда все сделано правильно.


Теперь, когда вы раскрыли свой HTML, вот версия, которая работает. Я должен сказать, что много этого javascript - это потому, что ваш HTML не делает это так просто, как могло бы быть.

$(document).ready(function() {
    $(".headermenushow").hover(function() {
        // hide any previous dropdown menus
        $(".dropmenu").hide();

        var self = $(this);
        var timer = self.data("timer");

        // show the dropdown menu for this item
        self.next().show();

        // clear any previous timer for this menu
        if (timer) {
            clearTimeout(timer);
            self.data("timer", null);
        }

    }, function() {
        // hide only on a delay so that user can move
        // to the menu
        var self = $(this);
        var menu = self.next();
        var timer = self.data("timer");
        // clear any previous timer that might have been active
        if (timer) clearTimeout(timer);
        timer = setTimeout(function() {
            self.data("timer", null);
            // if mouse is not over the menu, then hide it
            if (!menu.data("hover")) {
                menu.hide();
            }
        }, 500);
        self.data("timer", timer);

    });

    // keep track of hover state on the menu
    $(".dropmenu").hover(function() {
        $(this).data("hover", true);
    }, function() {
        $(this).data("hover", false);
        $(this).hide();
    });
});

Рабочая демонстрация: http://jsfiddle.net/jfriend00/YJu6Q/

  • 0
    да, с моим скриптом много проблем. Сначала я изучил CSS, но не могу добиться того эффекта, который мне нужен для этого. Что касается пункта 2 - я понимаю, что это проблема, но setTimeout, похоже, не будет работать, если я не включу его в исходное событие.
  • 0
    попытался сделать это без setTimeout - просто используя задержку hide () и show () - но не смог заставить это работать должным образом. Вот пример: jsfiddle.net/H247x/2
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню