引用自http://www.cnblogs.com/lovesong/p/5004951.html


bug:

  1. 滚轮缩放,底层页面显示高度也会跟着移动;

  2. esc、上、下、左、右键在未点击当前iframe下,并没有生效;


修复:

  1. 未阻止滚轮事件冒泡;

  2. 图片查看是在新打开的html页面查看,在用户未点击情况下,焦点停留在底层页面,需在打开页面后自动为当前window对象获取焦点,并组织键盘事件冒泡


下附完整代码

/*
 * AppGo使用的 图片查看插件
 * Author : lufeng@bingosoft.net
 * Version: 1.0.0
 * Date : 2015/11/17
 */
(function($) {

var windowMargin = 8; //加多边距的宽高,使得图片看起来有边框效果
  
//图片查看器
$.fn.extend({
   
   photoGallery: function(options) {

      var isFirefox = navigator.userAgent.indexOf("Firefox") > -1 ;
      var MOUSEWHEEL_EVENT = isFirefox ? "DOMMouseScroll" : "mousewheel";
      var defaults = {
          //图片缩放倍率
         ratio : 1.2, 
         //右下角缩略图宽度
         thumbnailsWidth : 180, 
         //右下角缩略图高度
         thumbnailsHeight : 120, 
         //HTML模版
         template : {
            //操作工具
            OPERTATION : '<div class="oper">' +
                        '<span class="prev"><i class="icon_tool-prev"></i></span>' +
                        '<span class="next"><i class="icon_tool-next"></i></span>' +
                      '</div>' +
                      '<div class="tool">' +
                        '<div class="toolct">' +
                           /*'<span class="oper_fullscreen" title="查看全屏"><i class="icon_tool-fullscreen"></i></span>' +*/
                           '<span class="oper_bigger" title="放大图片"><i class="icon_tool-bigger"></i></span>' +
                           '<span class="oper_smaller" title="缩小图片"><i class="icon_tool-smaller"></i></span>' +
                           '<span class="oper_rotate" title="向右旋转"><i class="icon_tool-rotate"></i></span>' +
                            /*'<span class="oper_download" title="下载图片"><i class="icon_tool-download"></i></span>' +*/
                        '</div>' +
                      '</div>',
            //缩略图
            THUMBNAILS : "<div class='thumbnails'>" +
                        '<span class="thumbClose" title="关闭缩略图"><i class="icon_close-small"></i></span>' +
                        '<img ondragstart="return false;"/>' +
                        '<div class="thumbDrag"><span></span></div>' +
                      "</div>",
            //大图
            IMAGE : '<img class="p_w_picpath" ondragstart="return false;"/>'           
         }
      };
      
      var o = $.extend(defaults, options),
           $gallery = $(this);
       $gallery.append(o.template.OPERTATION).append(o.template.THUMBNAILS);    

       var $tool = $(this).find(".tool"),
         $fullscreen = $(this).find(".oper_fullscreen"),
         $bigger = $(this).find(".oper_bigger"),
         $smaller =  $(this).find(".oper_smaller"),
         $rotate = $(this).find(".oper_rotate"),
         $download = $(this).find(".oper_download"),
         $prev = $(this).find(".prev"),
         $next = $(this).find(".next"),
         $thumbnails = $(this).find(".thumbnails"),
         $p_w_picpath,
         $thumbImg,
         p_w_picpathWidth,
         p_w_picpathHeight,
         imgRatio,
         dragX,
         dragY,
         cW,
         cH,
         w,h,isVertical,
         thumbX,
         thumbY;

      //上一张
      $prev.on('click',function(){
          if(o.activeIndex > 0) o.activeIndex--;
         toggleImage(); 
       }).on("mouseover",function(e){
          if(o.activeIndex > 0)
                $(this).addClass("active");
      }).on("mouseout",function(e){
         $(this).removeClass("active"); 
      });     
     
      //下一张
       $next.on('click',function(){
          if(o.activeIndex < o.imgs.length -1) o.activeIndex++;
          toggleImage();
       }).on("mouseover",function(e){
          if(o.activeIndex < o.imgs.length -1)
                $(this).addClass("active");
      }).on("mouseout",function(e){
         $(this).removeClass("active"); 
      });
       
      //缩略图
       $thumbnails.css({
         height: o.thumbnailsHeight,
         width : o.thumbnailsWidth
      }).on("mouseenter",function(e){
         thumbX = -1;
      }).on("mousedown",function(e){
         thumbX=e.pageX || e.clientX;
         thumbY=e.pageY || e.clientY;

         cW = document.body.clientWidth;
         cH = document.body.clientHeight;
         e.stopPropagation(); 
      }).on("mousemove",function(e){
         if(thumbX > 0){
                var nextDragX=e.pageX || e.clientX;
            var nextDragY=e.pageY || e.clientY;
            var $td= $(this).find(".thumbDrag"),
                p_w_picpathWidth = $p_w_picpath.width(),
               p_w_picpathHeight = $p_w_picpath.height(),
               thumbImgWidth = $thumbImg.width(),
               thumbImgHeight = $thumbImg.height(),
               left =parseFloat($td.css("left")) +  (nextDragX - thumbX),
               top =parseFloat($td.css("top")) + (nextDragY - thumbY),
               w = $td.width(),
               h = $td.height(),
               it,
               il,
               maxL,
               maxT;
         
            if(isVertical){
               thumbImgWidth = [thumbImgHeight, thumbImgHeight = thumbImgWidth][0];
               p_w_picpathWidth = [p_w_picpathHeight, p_w_picpathHeight = p_w_picpathWidth][0];
            }
            it = (o.thumbnailsHeight - thumbImgHeight) / 2 ,
            il = (o.thumbnailsWidth - thumbImgWidth) / 2,
            maxL = o.thumbnailsWidth - w - il - 2, //减去2像素边框部分
            maxT = o.thumbnailsHeight - h - it - 2;
            
            if(left < il ) left = il;
            else if(left > maxL) left = maxL;
         
            if(top < it ) top = it;
            else if(top > maxT) top = maxT;
            
            $td.css({
               left : left,
               top : top
            })
            thumbX=nextDragX;
            thumbY=nextDragY;    

            if(p_w_picpathWidth < cW) left = (cW - p_w_picpathWidth) / 2;
            else left = -p_w_picpathWidth * (left-il) / thumbImgWidth;
          
            if(p_w_picpathHeight < cH ) top = (cH - p_w_picpathHeight) / 2;
            else top = -p_w_picpathHeight * (top-it) / thumbImgHeight;
         
            $p_w_picpath.offset({
               left : left,
               top : top
            });
         }
      }).on("mouseup",function(e){
         thumbX = -1;
      });
                
      $thumbnails.find(".thumbClose").on("click",function(){
         $thumbnails.hide();
      });
         
       //显示工具栏
      $gallery.on("mouseover",function(e){
         $tool.show();
      
      }).on("mouseenter",function(e){
         dragX = -1;
      }).on("mouseout",function(e){
         $tool.hide();
      }).on("mousedown",function(e){
         dragX=e.pageX || e.clientX;
         dragY=e.pageY || e.clientY;

         cW = document.body.clientWidth;
         cH = document.body.clientHeight;
         e.stopPropagation(); 
      }).on("mousemove",function(e){
         if(dragX > 0){
                var nextDragX=e.pageX || e.clientX;
            var nextDragY=e.pageY || e.clientY ;
            var o = $p_w_picpath.offset(),
               left =o.left +  (nextDragX - dragX),
               top =o.top + (nextDragY - dragY),
               w = $p_w_picpath.width(),
               h = $p_w_picpath.height();
         
            if(isVertical){
               w = [h, h = w][0];
            }
            if(w > cW){
               if(left > 0){
                  left = 0 ;
               }
               else if(left < cW - w){
                  left = cW - w;
               }
            }else{
               left = o.left;
            }
            if(h > cH){
               if(top > 0){
                  top = 0 ;
               }
               else if(top < cH - h){
                  top = cH - h;
               } 
            } else{
               top = o.top;
            }  
         
            $p_w_picpath.offset({
               left : left,
               top : top
            });
            dragX=nextDragX;
            dragY=nextDragY;     
            setThumbnails(); //缩略图拖拽点
         }
      }).on("mouseup",function(e){
         dragX = -1;
      });
            
      //全屏
      var isMax,preWidth, preHeight, preTop, preLeft;
      $fullscreen.on("click", function(){
         var parentD = window.parent.document,
            J = $(parentD.getElementById("J_pg"));
         if(!isMax){
            isMax = true;
            preWidth = document.body.clientWidth;
            preHeight = document.body.clientHeight;
            preTop = J.css("top");
            preLeft = J.css("left");
            J.css({
               top: 0,
               left : 0,
               width : parentD.body.clientWidth,
               height : parentD.body.clientHeight,
            });
         } else{
            isMax = false;
            J.css({
               top: preTop,
               left : preLeft,
               width : preWidth,
               height : preHeight
            });
         }
      });
     
      //放大图片
      $bigger.on("click", function(){
         biggerImage();
      });
     
      //缩小图片
      $smaller.on("click", function(){
         smallerImage();
      });
     
      //旋转
      $rotate.on("click", function(){
      
         var rotateClass = $p_w_picpath.attr("class").match(/(rotate)(\d*)/);

         if(rotateClass){
            var nextDeg = (rotateClass[2] * 1 + 90) % 360;
            $p_w_picpath.removeClass(rotateClass[0]).addClass("rotate" + nextDeg);
            $thumbImg.removeClass(rotateClass[0]).addClass("rotate" + nextDeg);
            resizeImage(nextDeg);
            resizeThumbImg(nextDeg);
            isVertical = nextDeg == 90 || nextDeg == 270;
         } else{
            $p_w_picpath.addClass("rotate90");
            $thumbImg.addClass("rotate90");
            resizeImage("90");
            resizeThumbImg("90");
            isVertical = true;
         }
      });

      //下载
      $download.on("click", function(){
         var imgUrl = $p_w_picpath.attr("src");
             if(!imgUrl) return;
         alert("没有找到兼容所有浏览器方法,所以暂不实现");
      });
     
      $(window).on("resize",function(){
         setImagePosition();
      });
      
      if(document.attachEvent){
         document.attachEvent("on"+MOUSEWHEEL_EVENT, function(e){
            mouseWheelScroll(e);
         });
      } else if(document.addEventListener){
         document.addEventListener(MOUSEWHEEL_EVENT, function(e){
            mouseWheelScroll(e);
         }, false);
      }  
      
      function mouseWheelScroll(e){
         window.onmousewheel=function(){
            return false
         };
            e.preventDefault();
         var _delta = parseInt(e.wheelDelta || -e.detail);
          //向上滚动
         if (_delta > 0) {
              biggerImage();
           }
           //向下滚动
           else {
               smallerImage();
           }
      }
      
      //键盘上下左右键
      document.onkeydown = function(e){
         e = e || window.event;

         if (e.keyCode) {
            e.preventDefault();
            if(e.keyCode == 37 ){ //left
                if(o.activeIndex > 0) o.activeIndex--;
               toggleImage(); 
            }
            if(e.keyCode == 39 ){ //right
                 if(o.activeIndex < o.imgs.length -1) o.activeIndex++;
                toggleImage();
             }
            if(e.keyCode == 27 ){ // ESC键 CLOSE
               $(".closeWin").click();
            }
            if(e.keyCode == 38 ){ // 使用上下键缩放图片
               biggerImage();
            }
            if(e.keyCode == 40 ){
               smallerImage();
            }
         }
      };

      function init(){
          toggleImage();
       
          $(o.imgs).each(function(i, img){
             $(o.template.IMAGE)
                .appendTo($gallery)
                .attr("src", img.url)
                .attr("index", i)
                .css({
                  width : img.imgWidth,
                  height : img.imgHeight,
                  left : (cW - img.imgWidth)/2,
                  top: (cH - img.imgHeight)/2
           //   }).on("dblclick", function(){换为鼠标单击事件
            }).on("onclick", function(){ 
               app.window.close();
            });
          });
          $p_w_picpath = $(".p_w_picpath[index='"+o.activeIndex+"']", $gallery).addClass("active");
      }
     
      function toggleImage(){
          p_w_picpathWidth = o.imgs[o.activeIndex].imgWidth;
              p_w_picpathHeight = o.imgs[o.activeIndex].imgHeight;
              imgRatio = p_w_picpathWidth/ p_w_picpathHeight;
           cW = document.body.clientWidth;
         cH = document.body.clientHeight;
         $(".p_w_picpath", $gallery).removeClass("active");
         $p_w_picpath = $(".p_w_picpath[index='"+o.activeIndex+"']", $gallery).addClass("active").css({
            width : p_w_picpathWidth,
            height : p_w_picpathHeight
         }).removeClass("rotate0 rotate90 rotate180 rotate270");
         $thumbImg = $thumbnails.find("img").attr("src", o.imgs[o.activeIndex].url);    
         $thumbnails.find("img").removeAttr("class").removeAttr("style");
         isVertical = false;
         $thumbnails.hide();
         $prev.removeClass("active");
         $next.removeClass("active");
         setImagePosition();
      }  

      function biggerImage(){
         var w = $p_w_picpath.width(),
            h = $p_w_picpath.height(),
            nextW = w * o.ratio,
            nextH = h * o.ratio;
         if(nextW - w < 1) nextW = Math.ceil(nextW);
         var percent =  (nextW / p_w_picpathWidth * 100).toFixed(0) ;
         if(percent > 90 && percent < 110){
            percent = 100;
            nextW = p_w_picpathWidth;
            nextH = p_w_picpathHeight;
         }
         else if(percent > 1600) {
            percent = 1600;
            nextW = p_w_picpathWidth * 16;
            nextH = p_w_picpathHeight * 16; 
         }

         $p_w_picpath.width(nextW).height(nextH);
         setImagePosition();
         showPercentTip(percent);
         showThumbnails(nextW, nextH);
      }
     
      function smallerImage(){
         var w = $p_w_picpath.width(),
            h = $p_w_picpath.height(),
            nextW,
            nextH;
         var percent =  (w / o.ratio / p_w_picpathWidth * 100).toFixed(0) ;
         if(percent < 5) {
            percent = 5;
            nextW = p_w_picpathWidth / 20;
            nextH = p_w_picpathHeight / 20;
         }
         else if(percent > 90 && percent < 110){
            percent = 100;
                nextW = p_w_picpathWidth;
            nextH = p_w_picpathHeight;
         } else{
            nextW = w / o.ratio;
            nextH = h / o.ratio; 
         }
       
         $p_w_picpath.width(nextW).height(nextH);
         setImagePosition();
         showPercentTip(percent);
         showThumbnails(nextW, nextH);
      }
     
      //显示缩略图
      function showThumbnails(width, height){
         if(isVertical) width = [height, height = width][0];
         if(width > document.body.clientWidth || height > document.body.clientHeight){
            $thumbnails.show();
            setThumbnails();
         } else{
            $thumbnails.hide();
         }    
      }
     
      //重置图片宽高
      function resizeImage(rotateDeg){
      
         var mH = document.body.clientHeight - windowMargin,
            mW = document.body.clientWidth - windowMargin;
         if(rotateDeg == '90' || rotateDeg == '270'){
            mW = [mH, mH = mW][0];
         }

         var width, height;
         width = Math.min(p_w_picpathWidth, mW);
         height = Math.min(p_w_picpathHeight, mH);
      
         if(width / height > imgRatio){
            width = height * imgRatio;
         } else{
            height = width / imgRatio;
         }

         $p_w_picpath.css({
            width:width,
            height:height
         });
         setImagePosition();
      }
     
      function resizeThumbImg(rotateDeg){
         var maxW = o.thumbnailsWidth, maxH = o.thumbnailsHeight;
         if(rotateDeg == '90' || rotateDeg == '270'){
            maxW = [maxH, maxH = maxW][0];
         }
         $thumbImg.css({
            maxWidth : maxW,
            maxHeight : maxH
         });
         $thumbnails.hide();
      }
     
      //显示百分比提示
      function showPercentTip(percent){
          $gallery.find(".percentTip").remove();
         $("<div class='percentTip'><span>"+percent+"%</span></div>").appendTo($gallery).fadeOut(1500);
      }
     
      //设置图片位置
      function setImagePosition(){
         var w = $p_w_picpath.width(),
             h = $p_w_picpath.height(),
            cW = document.body.clientWidth,
            cH = document.body.clientHeight;

         var left = (cW - w)/2,
            top = (cH - h)/2;

         $p_w_picpath.css("left", left +"px").css("top", top+"px");
      }
     
      //设置缩略图拖拽区域
      function setThumbnails(){
         var $img = $thumbnails.find("img"),
            sW = $img.width(),
            sH = $img.height(),
            w = $p_w_picpath.width(),
            h =  $p_w_picpath.height(),
            imf = $p_w_picpath.offset(),
            imfl = imf.left,
            imft = imf.top,
            cW = document.body.clientWidth,
            cH = document.body.clientHeight,
            tW,
            tH,
            tl,
            tt;
   
         if(isVertical){
            sW = [sH, sH = sW][0];
            w = [h, h = w][0];
         }

         tW = sW / (w / cW);
         if(w < cW) tW = sW;
         tH = sH / (h / cH);
         if(h < cH) tH = sH;
         tl = (o.thumbnailsWidth - sW)/2 + -imfl/w * sW ;
         if(w < cW) tl = (o.thumbnailsWidth - sW)/2;
         tt = (o.thumbnailsHeight - sH)/2 + -imft/h * sH ;
         if(h < cH) tt = (o.thumbnailsHeight - sH)/2;
         $thumbnails.find(".thumbDrag").css({
            width: tW,
            height: tH,
            left: tl,
            top: tt
         });
      }
     
      init();
      return this;
   }
});
  
$.extend({
   //打开图片查看器
   openPhotoGallery : function(obj){

      // $('html').css('overflow', 'hidden');
      var $img = $(obj),
         imgUrl = $img[0].src;
      if(!imgUrl) return;

      //HTML5提供了一个新属性naturalWidth/naturalHeight可以直接获取图片的原始宽高
      var img = $img[0],
         imgHeight = img.naturalHeight,
         imgWidth = img.naturalWidth,
         ratio  = imgWidth / imgHeight,
         wH = 415,
         wW = 615,
         winHeight,
         winWidth,
         maxHeight = document.body.clientHeight - windowMargin * 2,
         maxWidth = document.body.clientWidth- windowMargin * 2;
   
      winWidth = Math.max(wW, imgWidth);
      winHeight = Math.max(wH, imgHeight);

      if(winWidth > maxWidth) {
         winWidth = maxWidth;
         winHeight =Math.max(wH, Math.ceil(winWidth / ratio));
         if(imgWidth > winWidth) {
            imgWidth = winWidth;
            imgHeight = Math.ceil(imgWidth / ratio);
         }           
      }
      
      if(winHeight > maxHeight) {
         winHeight = maxHeight;
         winWidth = Math.max(wW, Math.ceil(winHeight * ratio));
         if(imgHeight > winHeight) {
            imgHeight = winHeight;
            imgWidth = Math.ceil(imgHeight * ratio);
         }      
      }

      var $gallerys = $(obj).closest(".gallerys"),
         activeIndex=0,
         imgs = [];
      $gallerys.find(".gallery-pic").each(function(i, elem){
         var url = this.src,
            img = $(this)[0],
            nH = img.naturalHeight,
            nW = img.naturalWidth,
            ratio  = nW / nH,
            w = nW,
            h = nH;
         if(url == imgUrl){
            activeIndex = i;
            w = imgWidth;
            h = imgHeight;
         } 
         else{
            if(nW > winWidth) {
               w = winWidth;
               nH = h = Math.ceil(w / ratio);
               if( h > winHeight){
                  nH = h = winHeight;
                  w = Math.ceil(h * ratio);
               }
            }  
            if(nH > winHeight) {
               h = winHeight;
               w = Math.ceil(h * ratio);
               if( w > winWidth){
                  w = winWidth;
                  h = Math.ceil(w / ratio);
               }
            }  
         }
         imgs.push({
            url: url, 
            imgHeight : h,
            imgWidth : w
         });
      });
      
      localStorage["photoGalleryImgs"] = JSON.stringify(imgs); //因为此字符串可能是base64字符,appgo无法传
      localStorage["photoGalleryActiveIndex"] = activeIndex; 
      
      $("#J_pg").remove();
      $("<iframe></iframe>").appendTo("body")
         .attr("id", "J_pg")
         .attr("src", "/js/libs/jquery-photo-gallery/gallery.html")
         .css('z-index','9999')
         .css({
            position : "fixed",
            left : 0,
            top : 0,
            width : document.documentElement.clientWidth,
            height : document.documentElement.clientHeight,
            background: 'rgba(177, 178, 179, 0.6)',
            border: '1px solid #6D6D6D',
            'border-radius': '4px'

         });
         
      //打开iframe后将焦点移动到该元素,保证再不点击的情况下,设置的键盘事件生效
      var J_iframe = document.getElementById('J_pg').contentWindow;
      J_iframe.focus();


   },
   //做初始化
   initGallery : function(){

        var activeIndex = localStorage["photoGalleryActiveIndex"],
           imgs = JSON.parse(localStorage["photoGalleryImgs"]);
        
      localStorage.removeItem("photoGalleryActiveIndex");
      localStorage.removeItem("photoGalleryImgs");
       
      $(".gallery").photoGallery({
         imgs : imgs,
         activeIndex:activeIndex
      });

      $(".closeWin").click(function(){
         var _parent =  window.parent || window.top,
            _jg = _parent.document.getElementById("J_pg");
         $(_jg).remove();
      });
   }
});
  
})(jQuery);