I have a mousenter/mouseleave function that swaps out content when the element is being hovered over. however instead of it firing only on mouseenter it seems to keep continuously firing. I have created a jsfiddle here so hopefully it will be easier to understand.
Inside your rotate_start() and rotate_reset() functions you are triggering a hover event via this line:
jq('.product-image-container',super_prod).attr('hover','true');
Per JQuery docs, hover() method binds handlers for both mouseenter and mouseleave events. You're basically applying recursion unintentionally, as hover is fired as the mouse moves.
A simple fix for this is to replace .attr('hover','true'); with .data('hover',true);
Here is a scalable solution which should accomplish your objective:
HTML:
<div class="item">
<ul>
<li>
Main product photo
</li>
<li>
Alternate product photo 1
</li>
<li>
Alternate product photo 2
</li>
<li>
Alternate product photo 3
</li>
</ul>
</div>
CSS:
.item {
width:200px;
height:200px;
background-color:#F0F0F0;
border:1px solid #666;
}
.item ul li {
display:none;
}
JQuery:
var jq = jQuery.noConflict();
var timers = [];
var interval_seconds = 2;
jq('.item').mouseenter(function() {
// Scope this
var _this = jq(this);
// Self-executing function
(function cycle() {
// Recursive setTimeout accommodates for animation time - setInterval wont
timers['item'] = setTimeout(function() {
// Grab the currently visible photo, and the next photo
var _this_li = _this.find('li:visible');
var _next_li = _this_li.next();
// If there is no next photo, cycle back to first photo
if (_next_li.length == 0) {
_next_li = _this.find('li:first-child');
}
// Animate the rotation
_this_li.fadeOut('slow', function() {
_next_li.fadeIn('slow', function() {
// Recursion
cycle();
});
});
}, interval_seconds * 1000);
})();
});
jq('.item').mouseleave(function() {
// Stop the recursive setTimeout
clearTimeout(timers['item']);
// Scope this
var _this = jq(this);
// Grab the first photo in the list
var _first_li = _this.find('li:first-child');
// If the first photo in the list is not the currently visible photo, make it so.
if (_first_li.not(':visible')) {
_this.find('li:visible').fadeOut('slow', function() {
_first_li.fadeIn('slow');
});
}
});
jq(function() {
// Show the first photo on load
jq('.item').find('li:first-child').fadeIn('slow');
});
Demo: http://jsfiddle.net/AlienWebguy/EY8mM/1/
Related
I'm using this project: https://github.com/cowboy/jquery-throttle-debounce
My code is -sorta- working, but the debounce is being ignored.
So the waterfall function is called on every image load but the 2 second delay is not being respected. No errors are being shown.
What is the correct way to implement this?
I've been fiddling with this for 3 hours now, but can't find a solution.
(function($) {
$(document).ready(function(e) {
var $waterfall = $('.waterfall');
if ($waterfall.length) {
$waterfall.waterfall({});
}
// sort the waterfall when images are loaded
var $waterfall_images = $waterfall.find('img');
$waterfall_images.each(function(j, image) {
var $img = $(image);
$img.load(function() {
$.debounce(2000, $waterfall.waterfall('sort'));
});
});
});
})(jQuery);
<ul class="waterfall">
<li class="waterfall-item">
<a href="hidden link" title="hidden title">
<img alt="hidden alt" title="hidden title" data-srcset="hidden in this example" data-src="also hidden in this example" src="still hidden in this example" data-sizes="(min-width:440px) 300px, 95vw" class=" lazyloaded" sizes="(min-width:440px) 300px, 95vw"
srcset="think I'll hide this one too">
<span class="waterfallImgOverlay"></span>
</a>
</li>
</ul>
You are calling the method, not assigning a reference. Easiest thing, wrap it in a function. Second thing is debounce returns a method, so you need to store what it returns and than call that method.
(function($) {
$(document).ready(function(e) {
var $waterfall = $('.waterfall');
if ($waterfall.length) {
$waterfall.waterfall({});
}
var waterfallSort = $.debounce(2000, function(){ $waterfall.waterfall('sort'); });
// sort the waterfall when images are loaded
var $waterfall_images = $waterfall.find('img');
$waterfall_images.each(function(j, image) {
var $img = $(image);
$img.load( waterfallSort );
});
});
})(jQuery);
I want to create multiple thumbnails with the same .class. The thumbnail div contains 3 other divs. The first on is an image, the second one is a description which appear on mouseenter and the third one is a bar which change the opacity.
When the mouse hovers above the .thumbnail both elements should execute their function.
My Problem is that now every thumbnail executes the function, so every thumbnail is now highlighted. How can I change this so only one Thumbnail highlights while hovering above it?
HTML:
<div class="thumbnail">
<div class="thumbnail_image">
<img src="img/Picture.png">
</div>
<div class="thumbnail_describe">
<p>Description</p>
</div>
<div class="thumbnail_footer">
<p>Text</p>
</div>
</div>
jQuery:
$(document) .ready(function() {
var $thumb = $('.thumbnail')
var $thumb_des = $('.thumbnail_describe')
var $thumb_ft = $('.thumbnail_footer')
//mouseover thumbnail_describe
$thumb.mouseenter(function() {
$thumb_des.fadeTo(300, 0.8);
});
$thumb.mouseleave(function() {
$thumb_des.fadeTo(300, 0);
});
//mouseover thumbnail_footer
$thumb.mouseenter(function() {
$thumb_ft.fadeTo(300, 1);
});
$thumb.mouseleave(function() {
$thumb_ft.fadeTo(300, 0.8);
});
});
You code behave like this because you apply the fadeTo function to the $thumb_des and $thumb_ft selectors which contain respectively all the descriptions and footers of the page.
Instead, you should select the description and footer of the thumbnail triggering the mouse event, inside the mousenter or mouseleave functions.
Another thing you could change to optimize your code is to use only once the event listening functions, and perform both actions on the description and on the footer at the same time:
$thumb.mouseenter(function() {
var $this = $(this)
$this.find('.thumbnail_describe').fadeTo(300, 0.8);
$this.find('.thumbnail_footer').fadeTo(300, 1);
});
full working jsfiddle: http://jsfiddle.net/Yaz8H/
When you do:
$thumb_des.fadeTo(300, 0.8);
it fades all nodes in $thumb_des. What you want is to fade only the one that corresponds to the correct node in $thumb.
Try this:
for (i = 0; i < $thumb.length; i++)
{
$thumb[i].mouseenter(function (des) {
return function() {
des.fadeTo(300, 0.8);
};
}($thumb_des[i]));
});
}
You'll want to access the child objects of that particular thumbnail, something like this would work:
$(this).children('.thumbnail_describe').fadeTo(300, 0.8);
Here is a fiddle example.
I have the following code for my popup menu, the parent link is the top level link. It causes a popup to show. Popup fades in and fades out when the mouse enters and exits parent link.
However, I need it to not fade out the popup, if the mouse is over the popup! At the moment, as soon as the mouse enters the popup it fades it out. I need both divs to act as one for the hover, if this makes any sense!
// Hovering over the parent <li>
ParentLink.hover(
function()
{
Popup.fadeIn(300, function() {
});
},
function()
{
Popup.fadeOut(400, function() {
});
}
);
You should nest the popup inside the parent. This way when you move the mouse from the parent to the popup, the parent will still be in a mouse-over state because popup's mouse-over event is bubbled onto the parent. When the mouse is out of the parent (plus its children), mouse-out event will fire on the parent.
Edit
If you are not able to (or want to) change the markup, one possibility is to move the elements to the recommended positions using jQuery, like:
ParentLink.append(Popup); // moves the Popup element from its current position
// and places it as the last child of ParentLink
Most probably you'll have to modify your CSS to match the changes so you may want to think first.
you could unbind the hover-event for the parentlink on completion of the fadein.
Popup.fadeIn(300, function() {
$(ParentLink).unbind('hover');
});
This is not a direct answer to your question but a hint how this could work.
Why don't you nest the the 2nd <div> into the first one, so the out will not occur?
<div id="ParentLink">
<div id="Popup"></div>
</div>
Have #ParentLink { display: relative; } and #Popup { display: absolute; } and you will be fine.
But for those menu's I would always use a nested unordered list structure like this one:
<ul id="topLevel">
<li id="level1item">
Link
<ul id="subLevel">
<li>
Link 2
</li>
</ul>
</li>
</ul>
As said, unbind the event while you are hover the popup and then re-bind it when you are hovering out :
ParentLink.hover(
handlerIn,
handlerOut
);
var handlerIn = function()
{
Popup.fadeIn(300, popupFadeIn);
};
var handlerOut = function()
{
Popup.fadeOut(400);
};
var popupFadeIn = function() {
$(ParentLink).unbind('hover');
$(this).mouseleave( function () {
$(ParentLink).hover(
handlerIn,
handlerOut
);
});
};
btw, I didn't tested this
You can try this:
var inn;
$('ParentLink').hover(function() {
inn = false;
$('p').fadeIn(1000);
},
function() {
$('Popup').bind('mouseenter mousemove',
function() {
inn = true;
}).mouseout(function() {
inn = false;
});
if (!inn) $('Popup').fadeOut(1000);
});
I have a big ul list. Like this:
<ul class="eerstelaag">
<li class=""><a title="?" href="/">? (14)</a>
<ul class="tweedelaag" style="display: none;">
<li>Roerstaafjes</li>
<li>Thee favorieten</li>
<li>Siropen</li>
</ul>
</li>
<li class=""><a title="?" href="/">? (14)</a>
<ul class="tweedelaag" style="display: none;">
<li>Roerstaafjes</li>
<li>Thee favorieten</li>
<li>Siropen</li>
</ul>
</li>
<li class=""><a title="?" href="/">? (14)</a>
<ul class="tweedelaag" style="display: none;">
<li>Roerstaafjes</li>
<li>Thee favorieten</li>
<li>Siropen</li>
</ul>
</li>
</ul>
And i have this javascript:
$(function()
{
var button = $("#assortiment ul.eerstelaag > li");
button.hover(function()
{
if( button.hasClass("open"))
{
var menuitem = $(this).find("ul");
menuitem.slideUp(600);
button.removeClass("open");
}
else
{
var menuitem = $(this).find("ul");
menuitem.slideDown(600);
button.addClass("open");
}
});
});
When i hover over the first li item. Then the ul in that li is coming and show. But now come the problem. When i going fast hover over the li items. The effect i going crazy. And when i going hover faster and faster. It is a crazy effect.
How can i fix this problem?
You're probably looking for the stop function, which will cancel any currently-running animations on the element. You'd use this on the siblings of the element you're about to animate.
Update: Re my comment below, it looks like avoiding chaotic behavior is much trickier than simply stopping the animation. Here's a rough take:
jQuery(function($) {
var button = $("#assortiment ul.eerstelaag > li"),
opening = null,
closing = null;
button.mouseover(function() {
var $this = $(this),
open;
if (!$this.hasClass('open')) {
// If there's an active close operation, cut it short
if (closing) {
closing.stop().css("height", "").hide();
closing = null;
}
// If there's an active opening operation, turn it into
// a closing operation
if (opening) {
closing = opening;
opening = null;
closing.stop().css("height", "").slideUp(600, clearClosing);
}
// Is any sibling open? If so, unmark it it...
open = $this.siblings('li.open');
open.removeClass('open');
if (!closing) {
// ...and since the sibling wasn't still actively
// opening (that's handled above), close it
closing = open.find('ul:first');
closing.stop().css("height", "").slideUp(600, clearClosing);
}
// Open
$this.addClass('open');
opening = $this.find('ul:first');
opening.slideDown(600, clearOpening);
}
});
// Callback used when we're done closing, to clear
// our tracker
function clearClosing() {
if (closing && closing[0] === this) {
closing = null;
}
}
// Callback used when we're done opening, to clear
// our tracker
function clearOpening() {
if (opening && opening[0] === this) {
opening = null;
}
}
});
Live example
Note that when stopping the animation, I had to explicitly clear the height because it could get left in an intermediate state by slideUp / slideDown. You could probably use classes for tracking the actively opening/closing items, rather than the vars I used.
I should mention that in the above I went with putting the "open" class on the li containing the ul, whereas in your original, the "open" class was on the ul itself. If it was purely a marker (you weren't using it in your stylesheets), great; if not, I expect you could modify the above to go back to using the "open" class on the ul, or update the stylesheets to use li.open > ul selector instead of the ul.open selector to style them.
I have a ul with around five <li> items. E.g.
<ul>
<li>Step 1 : Take food</li>
<li>Step 2 : Go Around</li>
<li>Step 3 : Deliver</li>
</ul>
Also I have links like
Previous
and
Next
I have to show the first li at first. Then when the next link is clicked, it should now show 2nd <li> and so on. Same for previous link. Please help.
following is the complete code:
$(document).ready(function()
{
var ul = $('ul');
// hide all li
ul.find('li').hide();
// make first li as current
ul.find('li').first().addClass('current').show();
// setup previous click handler
$('a#prev').click(function()
{
var prev = ul.find('li.current').prev();
if( prev.length )
{
ul.find('li.current').removeClass('current').hide();
prev.addClass('current').show();
}
});
// setup next click handler
$('a#next').click(function()
{
var next = ul.find('li.current').next();
if( next.length )
{
ul.find('li.current').removeClass('current').hide();
next.addClass('current').show();
}
});
});
have a look at the aptly named jQuery Cycle plugin.
http://www.malsup.com/jquery/cycle/scrollhv.html
If you are only showing one element, all you need to do is use the DOM tree as a search. If you want the next element, find the element that is currently being shown, hide it, and show its next sibling. If you are doing previous, then hide the current item and select the previous sibling.
If you are unsure of how to do this, just Google around for DOM navigation. It isn't too bad.
If at all possible, I would simply use some naming convention for your LI (in the id attribute) that you could very quickly select using jQuery. For instance, if your shown element is going to have a class that the rest won't have, you can select that element quickly using jQuery, grab its id, and modify it in some way to select the previous or next element.
as boerema said something along these lines (its untested!)
put a class "selected" on a li that starts as being shown
<ul>
<li>Step 1 : Take food</li>
<li class="selected">Step 2 : Go Around</li>
<li>Step 3 : Deliver</li>
</ul>
$("#prev").click(function(){
$(".selected").hide().removeClass("selected").prev().show().addClass("Selected");
});
$("#next").click(function(){
$(".selected").hide().removeClass("selected").next().show().addClass("Selected");
});
here is a quick demo : http://jsbin.com/oduli4
var width = 500;
var height = 250;
var slide = 0;
var speed = 500;
var size = 0;
$(document).ready(function() {
size = $('#slider').find('li').length;
$('#slider').find('ul').width(width * size).height(height);
$('#slider li, #slider img').width(width).height(height);
$('#next').bind('click',function() {
if(slide > img_width * (size - 1) *(-1)) {
slide -= width;
slider(slide);
}
});
$('#prev').bind('click',function() {
if(slide < 0) {
slide += width;
slider(slide);
}
});
});
function slider(slideMargin) {
$('#slider ul').stop().animate({'left':slideMargin}, speed );
}