如何确保CSS:hover应用于动态添加的元素

时间:2012-10-29 11:23:53

标签: javascript jquery html css hover

我有一个脚本,当您将鼠标悬停在缩略图上时,可以动态地添加完整图像。我还给出了完整的图像CSS:悬停样式,使它们扩展到更大的宽度(通常它们被约束到缩略图的尺寸)。如果图像快速加载或缓存,这样可以正常工作,但是如果完整图像需要很长时间才能加载,并且在加载时不移动鼠标,那么一旦它出现,它通常会保持缩略图宽度(非:悬停样式),直到再次移动鼠标。我在所有尝试过的浏览器中都会遇到这种情况。我想知道这是不是一个错误,如果有办法修复或解决它。

值得注意的是,我也试图在.on('mouseenter')的Javascript中做同样的事情,并遇到了同样的问题。

由于问题的性质,可能很难重现,特别是如果您有快速连接。我从维基百科中选择了一张较大的照片进行演示,但要使其工作,您可能需要将其更改为特别大的或慢速域。另请注意,您可能必须清除缓存以进行连续重试。

如果仍然无法重现,可以在致电fullimage.load之前向anchor.show()添加人为延迟。

HTML:

<img id="image" src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Cairo_International_Stadium.jpg/220px-Cairo_International_Stadium.jpg" />

CSS:

.kiyuras-image {
    position: absolute;
    top: 8px;
    left: 8px;
    max-width: 220px;
}

.kiyuras-image:hover {
    max-width: 400px;
}

JS:

$(function () {

    var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';

    var fullimage = $('<img/>')
        .addClass('kiyuras-image')
        .load(function () {
            anchor.show();
        });

    var anchor = $('<a/>').hide().append(fullimage);

    $('body').prepend(anchor);

    $("#image").on('mouseenter', function () {
        fullimage.attr('src',fullimageurl);
        $(this).off('mouseenter');
    });

});

JS Bin

Updated JS Bin with 1.5-second delay added (Hopefully makes issue clearer)

再次:重现问题包括清除大图像的缓存,然后将鼠标悬停在原始图像上以初始加载大图像,然后在加载时不移动鼠标。预期的行为是大图像在最终加载时正确地使用:hover伪类。问题我发现当加载时间超过0.75秒时它不会占用:在你轻轻摇晃鼠标之前将其悬停。

编辑:有关我的用例的详细信息,请参阅我对@ LucaFagioli答案的评论。

编辑,续集:我以为我已经这样做了,但我只是试图在Firefox中重现这个问题而我却做不到。也许这是一个Chrome bug?

8 个答案:

答案 0 :(得分:7)

大多数浏览器仅在光标在元素上移动至少一个像素时才更新其hover个状态。当光标进入缩略图的img时,它会应用hover并运行您的mouseenter处理程序。如果您将光标保持不变直到加载完整尺寸的图片,那么旧的img(缩略图)将保持hover状态,新的状态将无法获得。

要使它在这些浏览器中运行,请将hover伪类移动到CSS中的公共父元素;例如,enclose both imgs in a span

答案 1 :(得分:2)

如果选择器正确,CSS将应用于所有元素,动态或其他。这包括所有伪类,并且会随着DOM中的属性发生变化而改变。

答案 2 :(得分:1)

[编辑:虽然我的解释可能很有意思,pozs' solution above更好,所以如果可以的话,我建议使用它。]

hover伪类规范是quite relaxed,关于何时应该激活它:

  

CSS没有定义哪些元素可能处于上述状态,   或状态如何进入和离开。脚本可能会改变   元素是否对用户事件做出反应,并且不同   设备和UA可能有不同的指向方式,或   激活元素。

特别是,当您在加载时更新锚元素的可见性时,它不会被激活。

你可以相当容易地解决这个问题:将hover样式复制到一个类,拦截光标移动到它最终会覆盖的元素上,并根据该元素从元素中添加或删除你的类。 / p>

演示: JS Bin (based on your delayed example)

<强>使用Javascript:

$("#image")
  .on('mouseenter', function () {
    fullimage.attr('src',fullimageurl).toggleClass('mouseover', true);
    $(this).off('mouseenter');
  })
  .mouseleave(function() {
    fullimage.toggleClass('mouseover', false);
  });

<强> CSS:

.kiyuras-image:hover, .kiyuras-image.mouseover {
    max-width: 400px;
}

答案 3 :(得分:0)

从你的问题的这一部分:“如果图像快速加载或缓存,这可以正常工作,但如果完整的图像需要很长时间才能加载,并且在加载时不移动鼠标,”

首先使用JavaScript“预加载”所有图像是否值得。这可能允许所有图像首先成功加载,对于连接速度较慢的人来说,它可能更友好一些。

答案 4 :(得分:0)

您可以这样做:http://jsfiddle.net/jR5Ba/5/

总之,在图片前添加加载布局,然后附加包含大图像的div,其中包含.load()回调以移除加载图层。

由于时间不够,上面的小提琴没有被简化和清理,但如果需要的话,我可以在明天继续工作。

$imageContainer = $("#image-container");    
$image = $('#image');

$imageContainer.on({
    mouseenter: function (event) {    
       //Add a loading class
       $imageContainer.addClass('loading');
       $image.css('opacity',0.5); 

       //Insert div (for styling) containing large image            
       $(this).append('<div><img class="hidden large-image-container" id="'+this.id+'-large" src="'+fullimageurl+'" /></div>');

       //Append large image load callback            
       $('#'+this.id+'-large').load(function() {
           $imageContainer.removeClass('loading');
           $image.css('opacity',1);
           $(this).slideDown('slow');
           //alert ("The image has loaded!");        
       });
    },            
    mouseleave: function (event) {
       //Remove loading class
       $imageContainer.removeClass('loading');
       //Remove div with large image 
       $('#'+this.id+'-large').remove();
       $image.css('opacity',1);             
    }        
});

修改

这是小提琴的新版本,包括正确大小的加载图层,当显示大图片时带有动画:http://jsfiddle.net/jR5Ba/6/

希望它会有所帮助

答案 5 :(得分:0)

在有要下载的图像之前,不要让IMG标记添加到DOM。这样,在加载图像之前,Load事件不会触发。这是修改后的JS:

$(function () {

    var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';

    var fullimage = $('<img/>')
        .addClass('kiyuras-image')
        .load(function () {
            anchor.show(); // Only happens after IMG src has loaded
        });

    var anchor = $('<a/>').hide();

    $('body').prepend(anchor);

    $("#image").on('mouseenter', function () {
        fullimage.attr('src',fullimageurl); // IMG has source
        $(this).off('mouseenter');
        anchor.append(fullimage); // Append IMG to DOM now.
    });

});

答案 6 :(得分:0)

我不是100%确定为什么:hover声明仅在轻微鼠标移动时触发。一个可能的原因可能是技术上你可能没有悬停元素。基本上你正在加载光标下的元素(直到大图像被完全加载,A元素有display: none,因此不可能处于:hover状态。与此同时,这并没有解释与较小图像的差异......

因此,一种解决方法是仅使用JavaScript并将:hover语句排除在等式之外。只需向用户显示两个不同的IMG元素,具体取决于悬停状态(在JavaScript中切换)。作为额外的优势,图像不必由浏览器动态地放大和缩小(Chrome中的视觉故障)。

请参阅http://jsbin.com/ifitep/34/

更新:通过使用JavaScript在大图片上添加.active类,完全可以继续使用原生CSS动画。见http://jsbin.com/ifitep/48

答案 7 :(得分:0)

我做到了,它适用于Chrome(版本22.0.1229.94 m): 我改变了css:

.kiyuras-image{
    position: absolute;
    top: 8px;
    left: 8px;
    max-width: 400px;
}
.not-hovered{
    max-width: 220px;
}

和脚本这样:

$(function(){
    var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';

    var fullimage = $('<img/>')
        .addClass('kiyuras-image')
        .load(function () {
            anchor.show();
        });

    var anchor = $('<a/>').hide().append(fullimage);

    $('body').prepend(anchor);

    $('.kiyuras-image').on('mouseout',function(){
        $(this).addClass('not-hovered');
    });
    $('.kiyuras-image').on('mouseover',function(){
        $(this).removeClass('not-hovered');
    });

    $("#image").one('mouseover', function(){
        fullimage.attr('src',fullimageurl);
    });
});

基本上我认为检测/渲染'悬停'状态是Chrome错误;事实上当我试图简单地将css更改为:

.kiyuras-image{
    position: absolute;
    top: 8px;
    left: 8px;
    max-width: 400px;
}
.kiyuras-image:not(:hover) {
    position: absolute;
    top: 8px;
    left: 8px;
    max-width: 220px;
}

它仍然无效。

PS:对不起我的英语。