0

I've been trying to learn jQuery and it's going pretty alright for me, I think. However, I can't seem to figure out how to make my coding efficient enough. Some times instead of using the callback function I do like a "double code", simply because I can't seem to figure out how to SKIP the "easing" thing, which makes me unable to use the callbacks.

I've tried to make a navbar which fades out using jQuery animate and opacity, however, sometimes when you hover over the navbar too fast it gets stuck at the opacity, and some times they just keep blinking and won't stop for a while. I can't seem to figure out how I can fix it, this is my code for the navigation bar:

<script type="text/javascript">
    $(document).ready()
    $("#navbar ul li.1 a").mouseover(function() {
        $("#navbar ul li.1 a").animate({
            opacity: 0.5
        }, 500, function() {
            $("#navbar ul li.1 a").mouseout(function() {
                $("#navbar ul li.1 a").animate({
                    opacity: 1.0
                }, 500, function() {
                });
            });
        });
    });
    $("#navbar ul li.2 a").mouseover(function() {
        $("#navbar ul li.2 a").animate({
            opacity: 0.5
        }, 500, function() {
            $("#navbar ul li.2 a").mouseout(function() {
                $("#navbar ul li.2 a").animate({
                    opacity: 1.0
                }, 500, function() {
                });
            });
        });
    });
    $("#navbar ul li.3 a").mouseover(function() {
        $("#navbar ul li.3 a").animate({
            opacity: 0.5
        }, 500, function() {
            $("#navbar ul li.3 a").mouseout(function() {
                $("#navbar ul li.3 a").animate({
                    opacity: 1.0
                }, 500, function() {
                });
            });
        });
    });
    $("#navbar ul li.4 a").mouseover(function() {
        $("#navbar ul li.4 a").animate({
            opacity: 0.5
        }, 500, function() {
            $("#navbar ul li.4 a").mouseout(function() {
                $("#navbar ul li.4 a").animate({
                    opacity: 1.0
                }, 500, function() {
                });
            });
        });
    });
</script>

I hope you can help me, thank you in advance!

1
  • 1
    Protip: have a look at .stop. Commented Jun 28, 2013 at 13:28

6 Answers 6

3

Use this to refer to the element on which the event was detected :

$("#navbar ul li a").mouseover(function() {
    var $a = $(this);
    $a.off('mouseout'); // unbind the previous mouseout event handlers
    $a.animate({
        opacity: 0.5
    }, 500, function() {
        $a.on('mouseout', function() {
            $a.animate({
                opacity: 1.0
            }, 500);
        });
    });
});
Sign up to request clarification or add additional context in comments.

5 Comments

Holy crap thats fast. Should probably note that binding event handlers inside event handlers isn't a very good idea.
^^ Yeah. You're adding a mouseout event handler every time the mouseover event occurs.
@Archer ya but removing it too
@roasted - it is now, yeah ;)
@roasted I edited, archer was right. But there's still room for improvement.
2

Some things to note:

  • Use .hover() and save yourself a couple of event handlers. This binding allows you to pass the mouseenter and mouseleave methods directly in.
  • Look at .stop() and how it can save you from animation hangs.
  • Take advantage of the multiple selectors jquery can use (it looks like the only difference in all of those is a class on the nested li element.

Assembling it all:

$('#navbar ul')                 // start with UL within #navbar
   .find('li.1,li.2,li.3,li.4') // find the <li>'s with classes 1-4
   .find('a')                   // find the <a>'s within those matches
  .hover(function(e){           // add binding
    // mouseenter
    $(this)                            // <a> target
      .stop()                          // stop current animation
      .animate({ opacity: 0.5 }, 500); // begin new animation
  }, function(e){
    // mouseleave
    $(this)                            // <a> target
      .stop()                          // stop current animation
      .animate({ opacity: 1.0 }, 500); // begin new animation

  });

Also, you could probably use .fadeTo() if you want to only adjust opacity, but that's your call. I don't know enough about your intent and you may just be playing with opacity as a test to get it working.

Working example

1 Comment

@roasted: Good point. mouseenter/mouseleave corrected. thanks! ;-)
0

Caching your selectors is more performant, but you can also chain your handlers for something that reads a little cleaner:

$("#navbar li a") // i'm assuming you want to target all li > a  elements in your nav (but maybe your markup is complicated enough to justify li.1 etc. 
  .mouseover(function() {
      $(this).animate({
          opacity: 0.5
      }, 500);
  }).mouseout(function() { // still refers to the same object
      $(this).stop().animate({
          opacity: 1.0
      }, 500 );
  });

Comments

0

The following article explains exactly how to fix your problem: http://www.learningjquery.com/2009/01/quick-tip-prevent-animation-queue-buildup

So basically adding stop() before starting the animation - by calling animate() - jQuery prevents building up an animation 'queue'.

Comments

0

Try this...

<script type="text/javascript">
    $(function() {
        $("#navbar ul li a").mouseover(function() {
            $(this).stop().animate({
                opacity: 0.5
            }, 500);
        }).mouseout(function() {
            $(this).stop().animate({
                opacity: 1.0
            }, 500);
        });
    });
</script>

I've replaced the multiple DOM lookups with just one. It finds all #navbar ul li a tags and adds relevant code, using this which is the selected element, for mouseover and mouseout. I've also added stop() to stop any running animations at the time, which will stop the issue you have when you mouseover and out a few times quickly.

Finally, I've used $(function() { }) instead of document.ready, just because that's how I do it.

I used to struggle with animation queues until I found out about stop(). From my understanding that's your main problem but the above code should work better for you regardless.

Comments

0

Could be using handlerInOut of hover method: { stealing Brad Christie's selector & idea... :) }

$('#navbar ul:has(li.1,li.2,li.3,li.4) a').hover(function () {
    if (!$(this).data('out')) $(this).data('out', true).stop().fadeTo(500, .5);
    else $(this).data('out', false).stop().fadeTo(500, 1);
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.