【问题标题】:jQuery Image Viewport Calculation Algorithm to Avoid Scrollbars避免滚动条的 jQuery 图像视口计算算法
【发布时间】:2012-09-23 13:19:31
【问题描述】:

我正在创建图像悬停效果,但我遇到了问题。当我将鼠标悬停在某些图像上时,滚动条 会出现,我想避免但不知道该怎么做。我相信它与视口和计算有关,但不确定是如何完成的。

Example Here

JSBin Code

代码如下:

$('.simplehover').each(function(){
    var $this = $(this);        
    var isrc = $this[0].src, dv = null;
                        
    $this.mouseenter(function(e){
        dv = $('<div />')
            .attr('class', '__shidivbox__')
            .css({
                display: 'none',
                zIndex : 9999,
                position: 'absolute',
                top: e.pageY + 20,
                left: e.pageX + 20
            })
            .html('<img alt="" src="' + isrc + '" />')
            .appendTo(document.body);           
        dv.fadeIn('fast');
    })
    .mouseleave(function(){
        dv.fadeOut('fast');
    });         

});

任何人都可以帮助我如何使悬停的图像出现在滚动条不出现的地方吗? (当然,如果图像尺寸非常大,我们不能避免滚动条)

我只想在缩放时显示原始图像,同时尽可能避免滚动条。

请注意,我计划将其转换为 jQuery 插件,因此我不能强制插件用户将 overflow 设置为 hidden。解决方案与 viewportlefttopscroll widthheight 有关, window width/height 属性,我可以稍后将其合并到插件中。


更新:

我想出了这个:

http://jsbin.com/upuref/14

但是,它非常非常 hacky,并不是 100% 完美的。我正在寻找更好的算法/解决方案。我见过很多悬停插件可以很好地做到这一点,但由于我不擅长这个,所以我不能做得很好。例如,Hover Zoom Chrome Plugin 在根据大小在适当位置显示悬停图像方面做得很好。

【问题讨论】:

  • 滚动条是什么意思?你是说窗口的滚动条吗?在您的示例中,我没有看到任何滚动条。
  • 您可以隐藏滚动条.. 但这不是所需的输出。如果图像真的很大,你希望它是怎样的?
  • 就个人而言,我会检查视口宽度并根据该值更改较大图像的大小。如果某人的屏幕很窄(例如上网本、纵向模式下的宽屏显示器等),无论您如何放置它们,图像都可能会离开页面的一侧。您可能希望它们出现在缩略图行之间(或在它们之前)......或使用灯箱方法。
  • 这里有一个解决方案:jsbin.com/upuref/4 但是它不是 100% 完美的。需要更好的计算算法。

标签: javascript jquery css


【解决方案1】:

像这样:

html{overflow-x:hidden;}
html{overflow-y:hidden;}

您只需将这些定义添加到您的 CSS 中即可。

使用调整大小更新:这是用于在水平和垂直方向BOTH调整图片大小和重新定位图片的 mouseenter 代码。现在,无论 HOVER 图像出现在哪里,它的大小和位置都会被调整为始终完整显示且未剪切。就滚动条而言,如果您显示的缩略图超出了页面的容量,甚至在 HOVER 图像出现之前您就会有滚动条。

最终和工作更新:因为您专注于隐藏滚动条,我认为您忽略了一个事实,即如果您放置的缩略图超出视口可以包含的数量,滚动条无论如何都会显示出来,并且因此,由于用户可以向下滚动文档,因此在计算悬停图像的位置时,不仅需要考虑调整大小,还需要考虑 scrollTop 位置! FINAL JSBIN HERE,无论 scrollTop 在哪里,无论视口大小如何,所有图片都显示 RESIZED 和 FULL。

$this.mouseenter(function () {

    dv = $('<div />')
          .attr('class', '__shidivbox__')
          .css({
            'display': 'none',
            'z-index': 9999,
            'position': 'absolute',
            'box-shadow': '0 0 1em #000',
            'border-radius': '5px'
          })
          .html('<img alt="" src="' + isrc + '" />')
          .appendTo(document.body);

    var DocuWidth = window.innerWidth;
    var DocuHeight = window.innerHeight;

    var DvImg = dv.find('img');

    var TheImage = new Image();
    TheImage.src = DvImg.attr("src");

    var DivWidth = TheImage.width;
    var DivHeight = TheImage.height;

    if (DivWidth > DocuWidth) {

        var WidthFactor = (DivWidth / DocuWidth) + 0.05;
        DivHeight = parseInt((DivHeight / WidthFactor), 10);
        DivWidth = parseInt((DivWidth / WidthFactor), 10);
    }

    var ThumbHeight = $this.height();
    var ThumbWidth = $this.width();
    var ThumbTop = $this.position().top;
    var ThumbLeft = $this.position().left;

    var SpaceAboveThumb = ThumbTop - $(document).scrollTop();
    var SpaceBelowThumb = DocuHeight - ThumbTop - ThumbHeight + $(document).scrollTop();

    var MaxHeight = Math.max(SpaceAboveThumb, SpaceBelowThumb);

    if (DivHeight > MaxHeight) {

        var HeightFactor = (DivHeight / MaxHeight) + 0.05;
        DivHeight = parseInt((DivHeight / HeightFactor), 10);
        DivWidth = parseInt((DivWidth / HeightFactor), 10);
    }

    var HoverImgLeft = 0;
    var HoverImgTop = 0;

    if (SpaceBelowThumb > SpaceAboveThumb) {
        HoverImgTop = ThumbTop + ThumbHeight;
    } else {
        HoverImgTop = ThumbTop - DivHeight;
    }

    HoverImgTop = (HoverImgTop < 0) ? 0 : HoverImgTop;

    HoverImgLeft = (DocuWidth - DivWidth) / 2;

    dv.find('img').css({
        'width': DivWidth,
        'height': DivHeight,
        'border-radius': '5px'
    });

    dv.css({
        'left': HoverImgLeft,
        'top': HoverImgTop
    });

    dv.fadeIn('fast');
});

【讨论】:

  • 它通过隐藏滚动条来剪切图像我的意思是如果你可以将图像显示在左侧,滚动条应该不可见,也不需要overflow。所以 计算 是不需要的。我已经更新了问题。
  • 图片大于视口会怎样?
  • 请查看更新的答案和我的尝试以及对问题的更多解释。你的 CSS 解决方案不能回答这个问题:(
  • 我更新了 jsbin 以进行自动图像调整大小和定位:jsbin.com/upuref/11/edit 这更接近您想要做的吗?它水平调整大小和居中;不知道你想用垂直定位做什么。
  • 第二行图像正在剪切/显示一半图像。我希望你现在明白了:)
【解决方案2】:

嗯,这看起来很有趣。不管怎样,这里是my answer。我已经看了几天了,虽然我也会参与进来。以下将确保悬停的图像不会超出视口,并且如果图像的宽度大于可显示的可用空间,则图像的显示将被调整大小(您可以注释掉代码如果您不想要它,它会这样做。只需在代码中查找“resize”一词)。

var $document = $(document);
$('.simplehover').each(function(){
    var $this = $(this);
    // make sure that element is really an image
    if (! $this.is('img')) return false;

    var isrc = $this[0].src, ibox = null;

    if (! isrc) return false;
    ibox = $('<img />')
            .attr('class', 'simpleimagehover__shidivbox__')
            .css({
                display: 'none',
                zIndex : 99,
                MozBoxShadow: '0 0 1em #000', 
                WebkitBoxShadow: '0 0 1em #000',
                boxShadow: '0 0 1em #000',
                position: 'absolute',
                MozBorderRadius : '10px',
                WebkitBorderRadius : '10px',
                borderRadius : '10px'
            })
            .attr('src', isrc)
            .appendTo(document.body);          

    $this.bind('mouseenter mousemove', function(e) {
        $('.simpleimagehover__shidivbox__').hide();

        var left = e.pageX + 5, 
            top = e.pageY + 5,
            ww = window.innerWidth,
            wh = window.innerHeight,
            w = ibox.width(),
            h = ibox.height(),
            overflowedW = 0,
            overflowedH = 0;

        // calucation to show element avoiding scrollbars as much as possible - not a great method though
        if ((left + w + $document.scrollLeft()) > ww)
        {
            overflowedW = ww - (left + w + $document.scrollLeft());
            if (overflowedW < 0)
            {
               left -= Math.abs(overflowedW);
            }
        }

        // 25 is just a constant I picked arbitrarily to compensate pre-existing scrollbar if the page itself is too long
        left -= 25;
        left = left < $document.scrollLeft() ? $document.scrollLeft() : left;

        // if it's still overflowing because of the size, resize it
        if (left + w > ww)
        {
            overflowedW = left + w - ww;
            ibox.width(w - overflowedW - 25);
        }


        if (top + h > wh + $document.scrollTop())
        {
            overflowedH = top + h - wh - $document.scrollTop();
            if (overflowedH > 0)
            {
                top -= overflowedH;
            }
        }

        top = top < $document.scrollTop() ? $document.scrollTop() : top;
        ibox.css({
            top: top,
            left: left
        });

        ibox.show();
    }); 


    $('.simpleimagehover__shidivbox__').mouseleave(function(){
        $('.simpleimagehover__shidivbox__').hide();
    });

    $document.click(function(e){
        $('.simpleimagehover__shidivbox__').hide();
    });

    $document.mousemove(function(e){
        if (e.target.nodeName.toLowerCase() === 'img') {
            return false;
        }

        $('.simpleimagehover__shidivbox__').hide();
    });
});

虽然我的解决方案本身并不完美,但您可能会在其中找到一些有用的东西来帮助您确定视口。此外,您可能需要考虑代码的性能。由于这是您正在构建的插件,因此您需要在将其公开之前进行一些优化。基本上,只要确保它不慢。

【讨论】:

    【解决方案3】:

    您可以根据可用宽度定位图像:http://jsbin.com/upuref/19/

    此演示考虑了用于定位图像的可用空间(即窗口宽度减去图像宽度)。我还改进了事件顺序,弹出窗口div 仅在图像加载后开始淡入。

    【讨论】:

    • 谢谢,但如果您将鼠标悬停在第二行图像上,它仍会显示垂直滚动条。在这种情况下,可以通过向上显示图像来避免滚动条。您可能还想查看我的更新,我什至已经这样做了,但正如我所说的,我的算法并不完美,因为我在各个网站上对其进行了测试,有时悬停的图像会出现在视口之外。
    • 您可以对垂直偏移重用相同的计算,但这种方法需要对事件处理进行重大重组,因为弹出图像几乎可以保证位于指针下方,这将触发 @缩略图上的 987654325@ 事件,并会立即淡出弹出窗口,如您在 an updated demo 中所见。解决这个问题超出了您当前问题的范围。
    • 我更新的演示应该会给你一个想法和事件:jsbin.com/upuref/14。然而,我使用的计算并不能在所有站点上完美运行。您可以使用任何事件,只要在悬停时显示弹出图像,然后在鼠标移开时将其隐藏。
    • 很抱歉,您的问题现在已经超出了可以直接回答的范围,而是进入了为您构建复杂功能的领域。我没有时间这样做,即使是赏金也不是什么激励措施。我将构建一个绝对定位的不可见 div 数组,以镜像大小并定位您的实际图像,并在它们上附加 mouseenter/mouseleave 处理程序;然后我会将弹出窗口div 置于 事件捕获层divs 并使用我已经提供的相同计算定位弹出窗口onmousemove
    【解决方案4】:

    我的回答也是(JSBin DEMO

    $('.simplehover').each(function(){
            var $this = $(this);
    
            // make sure that element is really an image
            if (! $this.is('img')) return false;
    
            var isrc = $this[0].src, dv = null;
    
            if (! isrc) return false;
    
            $this.mouseenter(function(e){
                // mouse x position
                var initXPos = e.pageX;
                var initYPos = e.pageY+20-$(window).scrollTop();
                var windowWidth = $(window).width();
                var windowHeight = $(window).height();
                // load original image
                var $img = $('<img/>');
                $img.on('load',function(eload) {
                    var widthImage = this.width;
                    var heightImage = this.height;
                    // set inline style for get sizes after (see problems webkit and cache)
                    $(this).css('width',widthImage);
                    $(this).css('height',heightImage);
                    var ratio = widthImage/heightImage;
    
                    var finalXPos = initXPos+widthImage>windowWidth? windowWidth-widthImage-5 : initXPos;
                    var finalYPos = initYPos;
    
                    var img = this;
    
    
                    // resize image if is bigger than window
                    if(finalXPos<0)  {
                        finalXPos = 0;
                        $img.css('width', windowWidth-10);
                        $img.css('height',(windowWidth-10)/ratio);
                    }
    
                    // If overflow Y
    
                    if(finalYPos+getSize($img,'height')>windowHeight) {
    
                        // calculate where is more space (top or bottom?)
                        var showOnTop = (windowHeight-initYPos-10)<windowHeight/2;
                        if(showOnTop) {
                            if(initYPos<getSize($img,'height')) {
                                $img.height(initYPos-30);
                                $img.width(getSize($img,'height')*ratio);
                            }
                            finalYPos = 0;
                            finalXPos = initXPos+getSize($img,'width')>windowWidth? windowWidth-getSize($img,'width')-5 : initXPos;
    
                        }else {
                            // show on bottom
                            if(windowHeight-initYPos<getSize($img,'height')) {
                                $img.height(windowHeight-initYPos-10);
                                $img.width(getSize($img,'height')*ratio);
    
                            }
                            finalXPos = initXPos+getSize($img,'width')>windowWidth? windowWidth-getSize($img,'width')-5 : initXPos;
                        }
                    }
                    dv = $('<div />')
                    .attr('class', '__shidivbox__')
                    .css({
                        display: 'none',
                        zIndex : 9999,
                        position: 'absolute',
                        MozBorderRadius : '5px',
                        WebkitBorderRadius : '5px',
                        borderRadius : '5px',
                        top: finalYPos+$(window).scrollTop(),
                        left: finalXPos
                    }).append($img)
                    .appendTo(document.body);           
                dv.fadeIn('fast');
                });
                // load the original image (now is the same, but I think is better optimize it)
                $img.attr("src",$this.attr("src"));
    
                function getSize($el,widthOrHeight) {
                    // horrible but working trick :)
                    return +$el.css(widthOrHeight).replace("px","");
                }
            })
            .mouseleave(function(){
                dv.fadeOut('fast');
            });         
    
        });
    

    此脚本使图像适应窗口大小并在需要时调整 x 位置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-10
      • 2018-08-07
      • 1970-01-01
      • 2012-01-14
      • 2018-03-26
      • 2020-01-19
      • 2011-10-19
      相关资源
      最近更新 更多