使用jQuery点击时保持图像悬停按钮

4
我有以下代码,当我悬停在按钮图像上时会提供悬停效果:

我有以下代码,当我悬停在按钮图像上时会提供悬停效果:

 $("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);
    });

这很好用。我现在有一个额外的要求:

我有三个排列在一行的按钮,它们都有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>

我仍然希望保留这个悬停效果,但现在我想改变它,使得当我点击一个图像时,它仍然显示悬停图像(即使当我将鼠标移出该图像时)。当我点击另一个按钮时,它应该从其他按钮中移除悬停效果。
注意:点击图像链接不会重定向到新页面(它们只是从js文件调用一些ajax)。
使用jQuery扩展以下代码以支持此功能的最佳方法是什么?似乎我需要在项目被点击后禁用mouseout处理程序,但我试图避免使用复杂的解决方案。
10个回答

10
你可以通过添加一个类、数据或属性来跟踪所点击的图片的活动状态,类似这样的代码可以实现这个功能。
$("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;
});

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

基本上,您需要删除hoverimage类及其在点击时的功能,使鼠标移出时不会发生mouseout事件。它还将hoverImage类恢复到所有兄弟元素上。

尽管如此,在我的点击处理程序中,您仍然可能需要还原兄弟元素的非悬停图像。

编辑:我为您制作了一个JSFiddle,并采用了不同的方法:

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

基本上,您需要创建一些类为hoverImage的链接,如下所示:
<a class="hoverImage"> </a>

然后您将它们声明为内联块,宽度和高度与您的图像相匹配,并为它们选择一个背景图像:
a.hoverImage {
    display: inline-block;
    width: 100px; height: 100px;
    background-image: url(http://placekitten.com/g/100/100);
}

然后,您可以创建一个CSS属性,在鼠标悬停时为它们提供新的背景图像,并且当它们具有“keepImage”类时:
a.hoverImage:hover, a.hoverImage.keepImage {
    background-image: url(http://placekitten.com/100/100);
}

自然地,如果你想要不同的图片,你需要为每个链接制作一个独特的图片。
最后,您需要编写一小段 JQuery 代码,当链接被点击时将类 keepImage 添加到它们,并从具有该类的任何兄弟元素中删除该类。
$("a.hoverImage").click(function() {
    $(this).siblings(".keepImage").removeClass("keepImage");
    $(this).addClass("keepImage");
});

如果你希望这个功能可以应用于更广泛的规模,不仅限于一组兄弟姐妹,比如整个页面,只需要将这个进行替换:

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

用这个:
$(".keepImage")

祝你好运!


2
我个人会做出相当多的更改:
首先,我不会依赖于交换文件名块的逻辑。您可能希望稍后更改您的约定,并且不想在JavaScript中搜寻并纠正事情。我会按照以下方式进行操作:
<img src="/Content/Images/1.png"
     data-active-image="/Content/Images/1_hover.png" />

如果未来你想要扩展此功能,那么天空是无限的:

<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" />

其次,我会将代码分离。我会有事件代码和图像选择代码。以下是我为图像选择代码编写的内容:

$.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));
    });
};

它接受来自事件代码的布尔值,以表示鼠标是否悬停在元素上。它会检查元素是否具有活动类或正在被悬停,如果是,就返回true,我们使用这个值来选择要使用的资源。接下来的部分用于将原始源缓存到“data-inactive-image”属性中。最后,我们设置源。
接着是事件代码。由于我们正在处理一种类似于单选按钮样式的分组,我建议拆分成多个图像组以放置在同一页上。在单击时,我们使来自原始选择器的所有图像失活,并使用前面提到的“active”类使当前图像处于活动状态。
$.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);
        });
};

为了将所有东西连接在一起,我们只剩下一条线:
$('.hoverImage').makeHoverGroup();

作为额外的好处,CSS知道JavaScript所知道的一切。悬停的图像具有.hoverImage:hover选择器(对于IE6支持的a:hover .hoverImage),活动图像具有.hoverImage.active选择器。
您可以在此处查看示例:http://fiddle.jshell.net/nDdzA/1/ 更新:修复了单击时的删除/重新添加。

1
如果点击同一元素两次(或更多),则可能希望避免对active类的删除和添加,以防止某些情况下的闪烁。顺便说一句,在Internet Explorer版本中,像*.hoverImage.active*这样的CSS选择器在这种情况下将无法正常工作,且: hover不支持图像(直到IE7)。 - Juicy Scripter
1
好的发现 Juicy。当我意识到IE6仅占美国市场份额不到1%(全球2.7%)时,我对IE6的担忧真的一落千丈。我们现在编写IE6的动力与曾经为Opera编写代码的动力相当。 - Brian Nickel

2

我认为如果您使用带有图像背景的“div”,会更加容易。将div的宽度和高度指定为与背景图像相同,并应用它。 在您的情况下,这尤其适用,因为您仅将这些图像用作某人单击的占位符。

一旦更改此设置,请指定:hover CSS修复。 您的新要求与识别当前活动图像有关。 为此,

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

     });

如果兄弟元素中已经存在活动类,则会将其删除,并突出显示当前元素。希望这解决了问题。

这听起来不错,但我认为您需要在页面上添加很多复杂性。您需要构建一个样式表,其中包含每个项目的正常和悬停/活动定义,并且需要确保您知道图像的宽度和高度。一个小变化是使用<div class="hoverItem"><img class="normal"><img class="active"></div>。然后,您可以使用CSS display属性控制哪个可见。 - Brian Nickel

1

这里是关于如何实现你想要的代码示例:http://jsfiddle.net/wCL2g/

Javascript 代码:

$("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');
});

希望这能有所帮助


1
我已将事件处理程序的工作转换为函数,以增强可读性。这可能需要进行一些清理才能用于生产代码,但对于这种规模的东西来说,这只是一个小问题。
当单击元素时,它会获得“isClicked”类,其余元素则会将其删除。所有匹配的元素都将传递给unHover函数。unHover函数与您的mouseout处理程序相同,除了它仅在缺少isClicked类的元素上起作用。
$("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

我会设置一个全局字符串,用于存储当前图像的src。然后在mouseout函数中使用它来测试当前图像是否已被点击,如果是,则跳过通常的mouseout过程。

在鼠标单击时,函数会查找具有“currentImage”src的图像,在找到后重置“currentImage”变量(允许mouseout函数正确运行),并手动执行mouseout。之后,它将“currentImage”变量设置为图像src(如上所述)。

此解决方案也很方便,因为它适合您的队列,并且对JS没有影响,对CSS和HTML也没有影响。

请查看下面的代码,如果您有任何问题,请告诉我:)

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);
    }
});

谢谢!:)


0
许多人建议使用jQuery属性和元数据处理来解决这个问题。在这里,我只是提出使用全局变量的方法。然而,你可能会遇到一些问题,所以让我解释一下解决方案:
(1). 如果你放置一个全局变量,请注意你锚点中的href=""。如果你触发了页面重新加载,你就回到了起点,这不好。所以我把它移除了。
(2). 你想在mouseover和mouseout中检查全局变量,做一些像...的事情。
if <triggered from current> return;   // disabling check    

问题在于在点击函数中,您想要执行类似以下的操作:
if <there is a current> current.trigger('mouseout');
<set new current>
current.trigger('mouseover')

但是由于我们通过禁用检查禁用了mouseout和mouseover,因此触发这些事件不起作用。

在这里您有两个选择:a)您可以将当前设置为null,触发这两个事件,然后将当前设置为所单击的选项;b)或者您可以将over/out效果与触发器隔离开来,以便您可以在两个位置调用它。

选项(a)是更复杂的单击处理程序,但更简单的鼠标处理程序。选项(b)需要进行更多的重构,但如果您喜欢使用其他jQuery功能,则可能是一个好主意。

(3). 因为我没有使用jQuery习语而是使用了您的方法,所以需要小心正则表达式,以使其匹配应该匹配的内容。我已经这样做了。

(4). 下面的代码将单击附加到锚点中,就像您提到的那样(尽管有些解决方案提到了图像本身)。这里的问题是如何将所单击的对象与相应的图像链接起来。在下面的代码中,jQuery的find()是关键。

(5). 在jQuery中最好不要使用全局变量,即在window对象级别上的变量。您仍然可以通过在涉及闭包之前声明变量来获得相同的结果,如下所示。此外,人们喜欢使用$表示包含jQuery包装对象的变量,我也这样做了。

(6). 最后,要注意对象比较。下面的代码确保我们比较DOM对象,因此请使用jQuery的get()

因此,这是修改后的HTML(已删除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>

(抱歉,图像URL与您的不同,我实际上测试了下面的代码)

方法(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>

而方法(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>

选项(a)保留了你的结构,但我认为选项(b)应该是你下一步并且也是我的首选。


0
使用jquery mousedownmouseup
$("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');
});

这不起作用,因为即使在单击图像后,mouseout仍然会删除图像。 - leora
哦,您想要类似于3种状态的东西:1.正常,2.鼠标悬停,3.点击。我说得对吗?!! - user405398
是的,我相信那是正确的。它必须知道当其他东西被悬停或点击时,它会从其点击状态中移除。 - leora

-3
如果您的链接不改变窗口位置,那么您可以按照Andreas的答案或类似的方法继续操作。如果它们改变了窗口位置,那么看起来更适合由服务器端脚本来处理。我不知道您正在使用哪个,所以我会在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 ?>

考虑到您可以来回切换,这绝对需要是客户端解决方案。 - leora
你为什么要给这个答案点踩?我明确说明了只有在你的window.locations改变时才应该使用它,当链接正常工作并且你的网站正在重新加载时。此外,你也可以在服务器端来回切换,所以这不是一个争论点。 - Przemek
@Przemek也投了反对票。问题明确要求使用jQuery,因此PHP答案不相关(通常JavaScript是可以接受的)。无论你给出了什么警告,这个答案只会混淆提问者和其他人找到问题的相关答案。 - Chao
问题字面上说:“请注意:点击图像链接不会重定向到新页面(它们只是从js文件调用一些ajax)”,因此窗口位置不会改变,无论如何。 - carlosayam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接