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

Posted

技术标签:

【中文标题】使用jQuery单击时保持图像悬停按钮【英文标题】:Keep image hover button when click using jQuery 【发布时间】:2011-11-30 15:56:36 【问题描述】:

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

 $("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 处理程序,但我试图避免复杂的解决方案。

【问题讨论】:

【参考方案1】:

您可以使用类/数据/属性之一跟踪单击图像的活动状态,这样就可以完成工作。

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

【讨论】:

【参考方案2】:
$("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 的小 sn-p,当它们被单击时,它会向它们添加类 keepImage,并从任何拥有它的兄弟姐妹中删除该类:

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

如果您希望它在更广泛的范围内工作,而不仅仅是一组兄弟,比如页面范围,只需替换它:

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

用这个:

$(".keepImage")

祝你好运!

【讨论】:

【参考方案3】:

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

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

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

     );

如果活动类已经存在于兄弟姐妹中,它将被删除并突出显示当前类。希望这能解决问题

【讨论】:

这听起来不错,但我认为您需要为页面添加很多复杂性。您需要为每个项目构建一个包含正常和悬停/活动定义的样式表,并且需要确保您知道图像的宽度和高度。一个小的变化是使用&lt;div class="hoverItem"&gt;&lt;img class="normal"&gt;&lt;img class="active"&gt;&lt;/div&gt;。然后,您可以使用 CSS display 属性控制哪一个可见。【参考方案4】:

我个人会做很多改变:

首先,我不会依赖交换文件名块的逻辑。您可能希望稍后更改您的约定,并且不希望必须通过您的 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 选择器(a:hover .hoverImage 用于 IE6 支持),活动图像具有 .hoverImage.active 选择器。

您可以在此处查看示例:http://fiddle.jshell.net/nDdzA/1/

更新修复了点击时删除/重新添加的问题。

【讨论】:

您可能希望避免在单击两次(或多次)时将 active 类删除和添加到同一元素,以防止在某些情况下闪烁。顺便说一句,在像 .hoverImage.active 这样的 Internet Explorer CSS 选择器版本中,在这种情况下会出错,并且图像不支持 :hover(直到 IE7)... 好收获多汁。当我意识到 IE6 仅占美国市场份额的不到 1%(全球 2.7%)时,我对 IE6 的关注度真的下降了。我们现在为 IE6 编写代码的动力与为 Opera 编写代码的动力差不多。【参考方案5】:

这里是如何实现你想要的示例代码: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');
);

希望对你有帮助

【讨论】:

【参考方案6】:

为了便于阅读,我将事件处理程序的工作方式纳入函数。这可能会在生产代码中进行一些清理,但对于这种大小的东西来说这是一个小问题。

当一个元素被点击时,它会获得“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);
    

【讨论】:

【参考方案7】:

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

在鼠标单击时,该函数会查找 src 为 currentImage 的图像,在找到后重置 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);
    
);

谢谢! :)

【讨论】:

【参考方案8】:

使用 jquery mousedown & 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');
);

【讨论】:

这不起作用,因为即使在单击图像后 mouseout 仍会删除图像 哦,你想要 3 种状态 1.正常,2.鼠标悬停,3.单击。我说的对吗?!! 是的,我相信这是正确的。它必须知道什么时候悬停或点击了其他东西,以便将其从点击状态中移除【参考方案9】:

许多人建议为此使用 jQuery 属性和元数据处理。这里我只是建议使用一个全局变量。但是,您可能遇到的问题很少,所以让我解释一下解决方案:

(1)。如果您放置一个 global 变量,请注意锚点中的 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')

但是由于我们通过禁用检查禁用了鼠标悬停和鼠标悬停,因此触发它们不起作用。

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

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

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

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

(5)。 jQuery 的最佳实践是不要使用全局变量,即窗口对象级别的变量。您仍然可以获得相同的结果,在所涉及的闭包上方声明变量,如下所示。此外,人们喜欢将 $ 用于保存 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>

(对不起,图片网址不是你的,我实际测试了下面的代码)

方法(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) 应该是您的下一步,这是我的偏好。

【讨论】:

【参考方案10】:

如果您的链接没有更改窗口位置,您可以继续使用 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 ?>

【讨论】:

它肯定需要作为客户端解决方案,因为您可以来回切换 你为什么不赞成这个答案?我特别指出,只有当您的 window.locations 发生更改、链接正常工作并且您的网站正在重新加载时,才应使用它。此外,您还可以在服务器端来回切换,因此这不是参数。 @Przemek 也投了反对票。专门针对 jQuery 提出的问题,因此 php 的答案是不相关的(JavaScript 通常是可以接受的)。无论您给出的答案有什么警告,只会使提问者和其他发现问题的人的相关答案变得混乱。 问题字面意思是“注意:点击图片链接不会重定向到新页面(他们只是从 js 文件中调用一些 ajax)”所以窗口位置不会改变,句号。

以上是关于使用jQuery单击时保持图像悬停按钮的主要内容,如果未能解决你的问题,请参考以下文章

当您使用 javascript 或 jquery 将鼠标悬停时,如何使图像或按钮发光?

单击按钮时暂时禁用悬停(jQuery)

jQuery hover - 按钮保持悬停效果

jquery slideUp on click,在 mouseleave 上悬停重置时停止

没有jQuery的悬停图像改变不透明度

当您使用 Javascript 单击或停止悬停时,如何使 CSS 悬停内容保持原位?