If you use jQuery, hold the hover button

I have the following code to provide a hover effect when you hover over a button image:

$("img.hoverImage") .mouseover(function () { var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png"; $(this).attr("src", src); }) .mouseout(function () { var src = $(this).attr("src").replace("_hover", ""); $(this).attr("src", src); }); 

This works great. Now I have an additional requirement:

I have three buttons in a row, each of which has class = "hoverImage".

 <a class="imageLink" href=""><img class="hoverImage" src="/Content/Images/1.png"/></a> <a class="imageLink" href=""><img class="hoverImage" src="/Content/Images/2.png"/></a> <a class="imageLink" href=""><img class="hoverImage" src="/Content/Images/3.png"/></a> 

I still want to keep this hover effect, but now I also want to change it, so when I click on the image, it holds the hover image (even when I exit this image). When I click on another button, it should remove the hover from the other buttons.

NOTE : clicking on image links is not redirected to a new page (they just call some ajax from the js file)

What is the best way to extend the code below to support this with jQuery? It seems I need to disable the mouseout handler after clicking the element, but I try to avoid a complicated solution.

+4
source share
10 answers

You can track the active state of a clicked image using one of the classes / data / attr, something like this will do the job.

 $("img.hoverImage").mouseover(function(){ if ($(this).is('.activeImage')) return; var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png"; $(this).attr("src", src); }).mouseout(function(){ if ($(this).is('.activeImage')) return; // Skip mouseout for active image var src = $(this).attr("src").replace("_hover", ""); $(this).attr("src", src); }).click(function(){ // remove previous active state $('.activeImage').not(this).removeClass('activeImage').trigger('mouseout'); // set new active state $(this).addClass('activeImage'); return false; }); 
+10
source
 $("img.hoverImage").click(function() { $(this).removeClass("hoverImage").addClass("keepImage"); $(this).siblings("img.keepImage").removeClass("keepImage").addClass("hoverImage"); }); 

Basically, you remove the hoverimage class and its functionality on click, making the mouseout event not occur when the mouse is output. It also restores the hoverImage class for all siblings.

You may still have to restore the non-hover image to your siblings in my click handler.

Edit: I made you a JSFiddle, and I took a different approach:

http://jsfiddle.net/jqWJN/2/

Basically, you make a few references with the hoverImage class, for example:

 <a class="hoverImage"> </a> 

Then you declare them as inline blocks with a width and height matching your image, and give them the background image of your choice:

 a.hoverImage { display: inline-block; width: 100px; height: 100px; background-image: url(http://placekitten.com/g/100/100); } 

Then you create a CSS property that gives them a new background image when they freeze and when they have a "keepImage" class:

 a.hoverImage:hover, a.hoverImage.keepImage { background-image: url(http://placekitten.com/100/100); } 

Naturally, you will need to create a unique one for each link if you want different pictures.

Finally, you make a small jQuery snippet that adds the keepImage class to them when clicked and removes the class from any siblings that have:

 $("a.hoverImage").click(function() { $(this).siblings(".keepImage").removeClass("keepImage"); $(this).addClass("keepImage"); }); 

If you want this to work on a larger scale than just one set of siblings, for example, across the page, just replace this:

 $(this).siblings(".keepImage") 

with this:

 $(".keepImage") 

Good luck

+3
source

I think it will be easier if you use a "div" with the image as the background. Specify the width and height of the div just like the background image, and apply it. This is especially applicable in your case when you use these images in the same way as a placeholder so that someone clicks on it.

Once that changes, specify: hover CSS fix. The new requirement that you have is related to the identification of the currently active image. For this

  $("<<placeholder - selector>>").click(function(){ $(this).addClass("active").siblings().removeClass("active"); }); 

If the active class is already present in the brothers and sisters, it will be deleted, and the current one will be highlighted. Hope this solves the problem.

+2
source

I personally would make a lot of changes:

Firstly, I will not depend on the logic of exchanging file names. You may want to change your conventions later and do not want you to look at your JavaScript-correcting stuff. I would do something in the following lines:

 <img src="/Content/Images/1.png" data-active-image="/Content/Images/1_hover.png" /> 

If in the future you want to expand this, the sky is the limit:

 <img src="/Content/Images/1.png" data-active-image="/Content/Images/1_hover.png" data-hover-image="/Content/Images/1_hover.png" data-disabled-image="/Content/Images/1_hover.png" /> 

Secondly, I would figure it out. I will have an event code and then an image select code. Here is what I put together for the image selection code:

 $.fn.updateImage = function(hovering) { return this.each(function() { var $el = $(this); var active = (hovering || $el.hasClass('active')); var image = active ? 'activeImage' : 'inactiveImage'; if(!$el.data('inactiveImage')) $el.data('inactiveImage', $el.attr('src')); $el.attr('src', $el.data(image)); }); }; 

It takes a boolean from the event code to say whether the mouse has ended or not. It checks whether an element has an active class or not. If it has an active class, or it hangs, this is true . We use this to choose which source to use. The next bit is used to cache the original source in the data-inactive-image attribute. Finally, we set the source.

Then we have the event code. Since we are dealing with a kind of grouping of buttons with buttons, I would break it down so that you have several groups of images on the page. When clicked, we make all the images from the original selector inactive and make the current image active using the active class mentioned earlier:

 $.fn.makeHoverGroup = function() { var $group = this; return this .mouseover(function() { $(this).updateImage(true); }) .mouseout(function() { $(this).updateImage(false); }) .click(function() { $group.not(this).removeClass('active').updateImage(false); $(this).addClass('active').updateImage(true); }); }; 

To tie it all together, we only have one line left:

 $('.hoverImage').makeHoverGroup(); 

As an added bonus, CSS knows everything JavaScript does. Hanging images have a .hoverImage:hover selector ( a:hover .hoverImage to support IE6), and active images have a .hoverImage.active selector.

Here you can see an example: http://fiddle.jshell.net/nDdzA/1/

Update Fixed delete / re-add by click.

+2
source

Here is a sample code on how to achieve what you want: http://jsfiddle.net/wCL2g/

Javascript code:

 $("img.hoverImage").mouseover(function() { var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png"; $(this).attr("src", src); // add class to state the element is hovered $(this).addClass('hover'); }).mouseout(function() { // don't trigger this function if element has clicked state if ($(this).hasClass('click')) { return; } var src = $(this).attr("src").replace("_hover", ""); $(this).attr("src", src); // remove hover class $(this).removeClass('hover'); }).click(function(e) { // disable the default click event e.preventDefault(); $(this).parent() // from the parent element .siblings() // find all the siblings elements <a>'s .find('img') // find <img> inside each sibling .removeClass('hover') // remove hover class .removeClass('click'); // remove click class // trigger the mouse over event for the image tag $(this).addClass('click').trigger('mouseover'); }); 

Hope this helps

+1
source

I handled event handlers in a function for readability. It could probably have been cleaned up a bit to go into production code, but this is a minor point for something of this size.

When an element is clicked, it gets the "isClicked" class, and the rest is deleted. All relevant elements are passed to the unHover function. The unHover function is the same as the mouseout handler, except that it only works with elements that do not contain the isClicked class.

 $("img.hoverImage") .mouseover(function () { makeHoverImage(this); }) .mouseout(function () { unHoverImage(this); }) .click(function(){ makeActive(elem); }); function makeActive(elem){ $("img.hoverImage").removeClass("isClicked"); $(elem).addClass("isClicked"); $("img.hoverImage").each(function(index,elem){ unHoverImage(elem); }); } function makeHoverImage(elem){ var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png"; $(this).attr("src", src); } function unHoverImage(elem){ if (!$(elem).hasClass("isClicked")){ var src = $(this).attr("src").replace("_hover", ""); $(this).attr("src", src); } } 
+1
source

I would set a global line that stores the current src image. Then use this in the mouseout function to check if the current image has been clicked if you bypass the normal mouse procedure.

When a mouse clicks, the function finds the image using src currentImage , resets the currentImage variable after it has been found (allowing the mouse function to run correctly), and manually performs the mouseout. Then it sets the variable currentImage to the src image (as mentioned above).

This solution is also convenient because it fits your turn and has minimal impact on JS and does not affect CSS and HTML.

Check out the code below and let me know if you have questions :)

 var currentImage = "0"; $("img.hoverImage") .click(function(){ $("img.hoverImage").each(function() { if($(this).attr("src")==currentImage){ currentImage = "0"; $(this).mouseout(); } }); currentImage = $(this).attr("src"); }) .mouseover(function () { var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png"; $(this).attr("src", src); }) .mouseout(function () { if($(this).attr("src") != currentImage){ var src = $(this).attr("src").replace("_hover", ""); $(this).attr("src", src); } }); 

Thanks!:)

+1
source

Use jquery mousedown and mouseup .

 $("img.hoverImage") .mouseenter(function () { var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png"; $(this).attr("src", src); }) .mouseleave(function () { var src = $(this).attr("src").replace("_hover", ""); $(this).attr("src", src); }); .mousedown(function () { $(this).trigger('mouseleave'); }) .mouseup(function () { $(this).trigger('mouseenter'); }); 
0
source

Many people have suggested using the jQuery attribute and metadata for this. Here, I simply suggest using a global variable. However, there are a couple of problems you encountered, so let me explain the solutions:

(1). If you put the global variable, beware of href = "" in your anchors. If you start reloading the page, you will return to square zero, but this is not good. So I deleted it.

(2). You want to check the global variable in mouseover and mouseout to do something like

 if <triggered from current> return; // disabling check 
Problem

is that in the click function you want to do something like

 if <there is a current> current.trigger('mouseout'); <set new current> current.trigger('mouseover') 

but since we disabled mouseout and mouseover by disabling validation , the start of these actions does not work.

Here you have two options: a) you can set the current to zero, activate these two events, and then set the current to one click; b) Or you can isolate the effect of overload / shutdown with a trigger so that you can call it in two places.

Option (a) is a more complex click handler, but a simpler handler. Option (b) requires a bit of refactoring, but if you prefer to go the way of using other jQuery functions, this is probably a good idea.

(3). Since I don't use jQuery idioms, but your approach, you need to be careful with the regex so that it matches what it should be. I have done it.

(4). The code below attaches the click to the anchors, as mentioned above (although some solutions mention the images themselves). The problem is how you snap the clicked object to the corresponding image. In the code below, jQuery find () is the key.

(5). In jQuery, it is best to use global variables, i.e. Variables at the window object level. You can still get the same result declaring a variable above the close, as shown below. Also, people like to use $ for variables that contain jQuery wrapped objects, and I did it.

(6). Lastly, beware of comparing objects. The code below allows you to compare DOM objects, so use jQuery get () .

So this is the corrected HTML (remote href):

 <a id="anchor1" class="imageLink" ><img class="hoverImage" src="images/1.png"/></a> <a id="anchor2" class="imageLink" ><img class="hoverImage" src="images/2.png"/></a> <a id="anchor3" class="imageLink" ><img class="hoverImage" src="images/3.png"/></a> 

(sorry the image urls are not like you, I really tested the code below)

Approach (a):

 <script type="text/javascript"> $(function() { var clickedImg = null; // this is common to all closures below $("img.hoverImage") .mouseover(function () { var $img = $(this); if ($img.get(0) == clickedImg) return; // note the improved matching ! var src = $img.attr("src").match(/[^_\.]+/) + "_hover.png"; $img.attr("src", src); }) .mouseout(function () { var $img = $(this); if ($img.get(0) == clickedImg) return; var src = $img.attr("src").replace("_hover",""); $img.attr("src", src); }); $("a.imageLink").click(function() { var oldClicked = clickedImg; clickedImg = null; // set to null to trigger events if (oldClicked) $(oldClicked).mouseout(); var newClicked = $(this).find('img').get(0); $(newClicked).mouseover(); clickedImg = newClicked; // redefine at the end alert($(this).attr('id') + " clicked"); // ajax call here }); }); </script> 

and approach (b):

 <script type="text/javascript"> $(function() { var clickedImg = null; // same global // refactor the mouse over/out - you could use other jQuery ways here function doOver($img) { var src = $img.attr("src").match(/[^_\.]+/) + "_hover.png"; $img.attr("src", src); } function doOut($img) { var src = $img.attr("src").replace("_hover",""); $img.attr("src", src); } $("img.hoverImage") .mouseover(function () { var $img = $(this); if ($img.get(0) == clickedImg) return; doOver($img); }) .mouseout(function () { var $img = $(this); if ($img.get(0) == clickedImg) return; doOut($img); }); $("a.imageLink").click(function() { if (clickedImg) doOut($(clickedImg)); clickedImg = $(this).find('img').get(0); doOver($(clickedImg)); alert($(this).attr('id') + " clicked"); // presumably your ajax call here }); }); </script> 

Option (a) preserves your structure, but I think that option (b) should be your next step, and these are my preferences.

0
source

If your links do not change the location of the window, you can continue with Andreas's answer or something similar. If so, it is more like running a server side script. I don't know which one you are using, so I will post an example in php.

 <?php foreach ($links as $i => $link): ?> <a class="imageLink" href="<?php echo $link ?>"> <img class="hoverImage" src="/Content/Images/<?php echo ($i == $selected) ? $i . "_hover" : $i ?>.png"/> </a> <?php endforeach ?> 
-3
source

All Articles