避免滚动条的jQuery图像视口计算算法

时间:2012-09-23 13:19:32

标签: javascript jquery css

我正在创建一个图像悬停效果,但我遇到了问题。当我将鼠标悬停在某些图像上时,会出现滚动条,我想避免但不知道如何操作。我认为它与视口和计算有关,但我不确定如何做到这一点。

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。该解决方案适用于视口顶部滚动宽度高度窗口宽度/高度属性,我稍后可以将其合并到插件中。


更新

我想出了这个:

http://jsbin.com/upuref/14

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

4 个答案:

答案 0 :(得分:3)

像这样:

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

您需要做的就是将这些定义添加到CSS中,然后就完成了。

使用调整大小更新:这是用于水平和垂直调整图片 BOTH 的鼠标中心代码。现在,无论HOVER图像出现在哪里,它都会调整大小并定位为始终显示完整且未切割。就滚动条而言,如果您显示的缩略图多于页面上可以容纳的缩略图,则即使在HOVER图像显示之前,您也会有滚动条。

最终和工作更新:因为您专注于隐藏的滚动条,我认为您忽略了这样一个事实:如果您放置的视口比视口可以包含的更多,滚动条无论如何都会显示出来因此,由于用户可以向下滚动文档,当您计算悬停图像的位置时,您不仅需要考虑调整大小,还要考虑scrollTop位置! FINAL JSBIN HERE ,无论视频大小在何处,无论视口大小是什么,所有图片都显示为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');
});

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

我的回答(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位置。

答案 3 :(得分:1)

嗯,这看起来很有趣。无论如何,这是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();
    });
});

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