js图片查看器 - 灵感来自于picasa

 

    本功能是为了解决运营对后台管理系统中用户上传的各种角度和尺寸的图片难以浏览的问题,于是花了两天时间写了这个插件,给大家分享。

    兼容现代浏览器,不兼容ie678,主要是一些效果无法实现。

    带有图片查看器的常用功能,UI设计和交互灵感来源于google的picasa。

    为了保证整体的清洁,界面没有使用任何图标,有需要的可以自行修改css。

 

    不知道什么原因插不了iframe,DEMO

 

    效果图:

demo

 

    代码如下:

 

js

js图片查看器 - 灵感来自于picasa
/**

 * 照片浏览

 * --

 * @author Lianer

 * @version 2015.06.11

 * @description 带有常用照片查看功能,包括缩放、自适应、移动、切换、旋转、下载,ie9+

 * @example

 *   var pv=new PhotoView();

 *   pv.add(["1.jpg", "2.jpg", "3.jpg"]);  // 追加列表

 *   pv.show();   // 显示

 *   pv.close();  // 关闭

 *   pv.aim(1);   // 定位到指定位置

 *   pv.reset();  // 重置

 */



(function () {

  "use strict";

  var PhotoView=window.PhotoView=function () {



    var createElement=function (type, className, parent) {

      var elem=document.createElement(type);

      if(className) elem.className=className;

      if(parent) parent.appendChild(elem);

      return elem;

    };



    var bindWheel=function (elem, fn, cancelBubble) {

      if("onwheel" in document){

        elem.onwheel=handler;

      }

      else if("onmousewheel" in document){

        elem.onmousewheel=handler;

      }

      else{

        return false;

      }

      return true;



      function handler(e) {

        e=window.event||e;

        var deltaX = e.deltaX ||        // wheel

                     -e.wheelDeltaX ||  // onmousewheel

                     0;                 // firefox,DOMMouseScroll不支持2D



        var deltaY = e.deltaY ||        // wheel

                     -e.wheelDeltaY ||  // onmousewheel

                     -e.wheelDelta ||   // 1D

                     e.detail ||        // firefox,DOMMouseScroll

                     0;



        deltaX=deltaX>0?1:deltaX<0?-1:0;

        deltaY=deltaY>0?1:deltaY<0?-1:0;



        fn(deltaY, deltaX, e);



        if(cancelBubble){

          if(e.preventDefault) e.preventDefault();

          if(e.stopPropagation) e.stopPropagation();

          e.cancelBubble=true;

          e.returnValue=false;

          return false;

        }

      }

    };



    

    var pv=function () {

      this.index=0;

      this.queue=[];

      var elem=this.elem={};

      // 外框

      elem.wrap=createElement("div", "photoview photoview_" + pv.size++);

      elem.wrap.setAttribute("tabindex", "0");

      // 容器

      elem.container=createElement("div", "photoview-container", elem.wrap);

      // 缩放指数

      elem.scaleValue=createElement("div", "photoview-scale-value", elem.container);

      elem.scaleValue.style.display="none";

      // 预览

      elem.view=createElement("div", "photoview-view", elem.container);

      elem.viewCache=createElement("img");

      // 控制栏

      elem.control=createElement("div", "photoview-control", elem.wrap);

      // 控制栏队列

      elem.controlQueue=createElement("div", "photoview-control-queue", elem.control);

      // 编辑

      elem.controlEdit=createElement("div", "photoview-control-edit", elem.control);

      // 放大

      elem.scaleUp=createElement("div", "photoview-scale-up", elem.controlEdit);

      // 缩小

      elem.scaleDown=createElement("div", "photoview-scale-down", elem.controlEdit);

      // 自适应

      elem.scaleAdapt=createElement("div", "photoview-scale-adapt", elem.controlEdit);

      // 上一张

      elem.prev=createElement("div", "photoview-prev", elem.controlEdit);

      // 下一张

      elem.next=createElement("div", "photoview-next", elem.controlEdit);

      // 逆时针旋转

      elem.rotateCCW=createElement("div", "photoview-rotate-ccw", elem.controlEdit);

      // 顺时针旋转

      elem.rotateCW=createElement("div", "photoview-rotate-cw", elem.controlEdit);

      // 下载

      if(window.Blob) elem.download=createElement("div", "photoview-download", elem.controlEdit);

      // 关闭

      elem.close=createElement("div", "photoview-close", elem.wrap);

      elem.close.innerHTML="关闭";



      document.body.appendChild(elem.wrap);



      this.$bind();

    };

    pv.prototype={

      // control定位

      aim: function (n) {

        var _this=this, elem=this.elem, queue=this.queue;

        if(n>queue.length-1){

          n=queue.length;

        }

        else if(n<0){

          n=0;

        }

        var target=elem.controlQueue.querySelectorAll("p");

        if(target){

          target=target[n];

        }

        if(target){

          var last=elem.controlQueue.querySelector(".active");

          if(last){

            last.className="";

          }

          target.className="active";

          elem.controlQueue.style.left=(elem.control.clientWidth/2-target.offsetLeft-target.offsetWidth/2)+"px";

          this.$view(this.queue[n]);

          this.index=n;

        }

        return this;

      },

      // 适应

      $adapt: function () {

        var _this=this, elem=this.elem, target=this.queue[this.index], 

          view=elem.view, 

          img=elem.viewCache, 

          container=elem.container,

          scale=target.scale;



        var imgSize={

          width: img.width,

          height: img.height,

          rate: img.width/img.height

        };

        var conSize={

          width: container.clientWidth, 

          height: container.clientHeight, 

          rate: container.clientWidth/container.clientHeight

        };



        if(target.scale==null){

          var coverage=0.7;

          if(imgSize.rate>conSize.rate){  // 更宽

            if(imgSize.width>conSize.width*coverage){

              target.scale=conSize.width/imgSize.width*coverage;

            }

            else{

              target.scale=1;

            }

          }

          else{

            if(imgSize.height>conSize.height*coverage){

              target.scale=conSize.height/imgSize.height*coverage;

            }

            else{

              target.scale=1;

            }

          }

        }

        target.width=imgSize.width*target.scale;

        target.height=imgSize.height*target.scale;

        target.left=((conSize.width-imgSize.width*target.scale)/2+target.x);

        target.top=((conSize.height-imgSize.height*target.scale)/2+target.y);

        view.style.width=target.width+"px";

        view.style.height=target.height+"px";

        view.style.left=target.left + "px";

        view.style.top=target.top + "px";

        view.style.transform="rotate(" + target.rotate + "deg)";

      },

      // 追加列表

      add: function () {

        var _this=this, elem=this.elem, queue=this.queue;

        var arg;

        for (var i = 0; arg=arguments[i]; i++) {

          if(!arg){

            return false;

          }

          if(arg.length){

            var a;

            for (var i = 0; a=arg[i]; i++) {

              checkType(a);

            }

          }

          else{

            check(arg);

          }

        }

        function checkType(mixed) {

          if(typeof mixed==="string"){

            var img=document.createElement("img");

            img.src=mixed;

            add(img, null, null);

          }

          else if(mixed.nodeName&&mixed.nodeName.toLowerCase()==="img"){

            add(mixed.getAttribute("data-source")||mixed.src, 

              mixed.getAttribute("data-rotate")||null, 

              mixed.getAttribute("data-scale")||null);

          }

          else{

            return false;

          }

        }

        function add(src, rotate, scale) {

          var q={

            src: src,  // 图片路径

            rotate: rotate||0,  // 旋转角度

            scale: scale,  // 缩放比例,null时会通过adapt计算以contain

            x: 0,  // x轴偏移

            y: 0   // y轴偏移

          };

          queue.push(q);

          var p=createElement("p", null, elem.controlQueue),

            img=createElement("img");

          p.style.cssText="opacity: 0;background-image: url(" + src + ");";

          p.photoview={

            index: queue.length-1

          };

          img.src=src;

          img.onload=function () {

            p.style.opacity="";

            this.onload=null;

          };

        }

        return this;

      },

      // 绑定事件

      $bind: function () {

        var _this=this, elem=this.elem, queue=this.queue;

        // 关闭

        elem.close.onclick=function () {

          _this.close();

        };

        // 窗口变化

        var resizeTimer=0, resizeHandler=function () {

          clearTimeout(resizeTimer);

          resizeTimer=setTimeout(function () {

            if(!_this.queue.length) return;

            elem.controlQueue.children[_this.index].click();

          }, 200);

        };

        if(window.addEventListener){

          addEventListener("resize", resizeHandler);

        }

        else if(window.attachEvent){

          attachEvent("onresize", resizeHandler);

        }

        // view.onload自适应

        elem.viewCache.onload=function () {

          elem.view.style.backgroundImage='url("' + this.src + '")';

          _this.$adapt();

        };

        // view缩放

        var scaleTipTimer=0, showScaleTip=function (scale) {

          if(window.console) console.log(scale);

          elem.scaleValue.innerHTML=parseInt(scale*100)+"%";

          elem.scaleValue.style.display="block";

          clearTimeout(scaleTipTimer);

          clearTimeout(scaleTipTimer+1);

          clearTimeout(scaleTipTimer+2);

          scaleTipTimer=setTimeout(function () {

            elem.scaleValue.style.opacity=1;

          }, 16);

          setTimeout(function () {

            elem.scaleValue.style.opacity=0;

          }, 1200);

          setTimeout(function () {

            elem.scaleValue.style.display="none";

          }, 1300);

        };

        bindWheel(elem.container, function (y, x, e) {

          if(!_this.queue.length) return;

          var target=queue[_this.index], 

            rate=1.2;

          if(y>0){

            target.scale=target.scale/rate;

          }

          else if(y<0){

            target.scale=target.scale*rate;

          }

          

          showScaleTip(target.scale);



          if(e.target===elem.view){

            // view内部定点缩放

            var position={

              // transition中的元素会使getBoundingClientRect、getComputedStyle、offsetLeft等无法取得最终值

              x: e.clientX-target.left-target.width/2,

              y: e.clientY-target.top-target.height/2

            };

            if(y>0){

              target.x=target.x-(position.x/rate-position.x);

              target.y=target.y-(position.y/rate-position.y);

            }

            else if(y<0){

              target.x=target.x-(position.x*rate-position.x);

              target.y=target.y-(position.y*rate-position.y);

            }

          }



          _this.$adapt();

        }, true);

        // view移动

        var moving=false, coord={x: 0, y: 0};

        elem.view.onmousedown=function (e) {

          e=window.event||e;

          moving=true;

          coord.x=e.clientX;

          coord.y=e.clientY;

          elem.view.style.zIndex=2;

        };

        // 离开事件绑定到wrap,防止禁止移动状态下(选中元素拖拽)发生bug

        elem.wrap.onmouseup=elem.wrap.onmouseout=function (e) {

          moving=false;

          elem.view.style.transition="";

          elem.view.style.zIndex="";

        };

        elem.view.onmousemove=function (e) {

          if(!_this.queue.length) return;

          if(moving){

            elem.view.style.transition="none";

            var target=_this.queue[_this.index];

            target.x=target.x+e.clientX-coord.x;

            target.y=target.y+e.clientY-coord.y;

            coord.x=e.clientX;

            coord.y=e.clientY;

            _this.$adapt();

          }

        };

        // 点击queue,定位到目标

        elem.controlQueue.onclick=function (e) {

          e=window.event||e;

          var target=e.srcElement||e.target;

          if(target.nodeName==="P"){

            _this.aim(target.photoview.index);

          }

        };

        // control滚动

        bindWheel(elem.control, function (y, x) {

          if(y>0){

            _this.aim(_this.index+1);

          }

          else if(y<0){

            _this.aim(_this.index-1);

          }

        }, true);

        // 捕获按键

        elem.wrap.onkeydown=function (e) {

          if(e.keyCode===27){

            _this.close();

          }

        };

        // 放大

        elem.scaleUp.onclick=function () {

          if(!_this.queue.length) return;

          var target=queue[_this.index];

          target.scale=target.scale*1.1;

          showScaleTip(target.scale);

          _this.$adapt();

        };

        // 缩小

        elem.scaleDown.onclick=function () {

          if(!_this.queue.length) return;

          var target=queue[_this.index];

          target.scale=target.scale/1.1;

          showScaleTip(target.scale);

          _this.$adapt();

        };

        // 自适应

        elem.scaleAdapt.onclick=function () {

          if(!_this.queue.length) return;

          var target=queue[_this.index];

          target.x=target.y=0;

          if(target.scale===1){

            target.scale=null;

          }

          else{

            target.scale=1;

          }

          _this.$adapt();

        };

        // 上一张

        elem.prev.onclick=function () {

          if(!_this.queue.length) return;

          _this.aim(_this.index-1);

        };

        // 下一张

        elem.next.onclick=function () {

          if(!_this.queue.length) return;

          _this.aim(_this.index+1);

        };

        // 顺时针旋转

        elem.rotateCW.onclick=function () {

          if(!_this.queue.length) return;

          queue[_this.index].rotate=(queue[_this.index].rotate+90)%360;

          _this.$adapt();

        };

        // 逆时针旋转

        elem.rotateCCW.onclick=function () {

          if(!_this.queue.length) return;

          queue[_this.index].rotate=(queue[_this.index].rotate-90)%360;

          _this.$adapt();

        };

        // 下载

        elem.download && (elem.download.onclick=function () {

          if(!_this.queue.length) return;

          var a=document.createElement("a");

          a.href=_this.queue[_this.index].src;

          a.download=/([^\/]+)$/.test(a.href)&&RegExp.$1||new Date().getTime()

          a.click();

        });

      },

      // 隐藏查看器

      close: function () {

        var style=this.elem.wrap.style;

        style.opacity=0;

        setTimeout(function () {

          style.display="none";

        }, 316);

        return this;

      },

      // 销毁

      destory: function () {

        // 暂时只移除dom

        this.elem.wrap.parentNode.removeChild(this.elem.wrap);

        return this;

      },

      // 清空列表

      reset: function () {

        this.queue.length=0;

        this.elem.controlQueue.innerHTML="";

        this.elem.view.style.cssText="";

        return this;

      },

      // 显示查看器

      show: function () {

        var _this=this, elem=this.elem, 

          style=elem.wrap.style;

          style.opacity=0;

          style.display="block";

        setTimeout(function () {

          style.opacity=1;

        }, 16);

        _this.aim(0);

        elem.wrap.focus();

        return this;

      },

      // 预览

      $view: function (target) {

        var _this=this, elem=this.elem;

        elem.viewCache.src=target.src;

      }

    };

    pv.size=0;

    return pv;

  }();



})();
View Code

 

css

js图片查看器 - 灵感来自于picasa
.photoview{

  display: none;

  position: fixed;left: 0;top: 0;right: 0;bottom: 0;z-index: 100;overflow: hidden;

  background: rgba(0, 0, 0, .8);

  transition: all 0.3s ease-out;

  moz-user-select: -moz-none;

  -moz-user-select: none;

  -o-user-select: none;

  -khtml-user-select: none;

  -webkit-user-select: none;

  -ms-user-select: none;

  user-select: none;

}

.photoview-container{

  position: relative;width: 100%;height: 100%;

}

.photoview-scale-value{

  position: absolute;left: 0;top: 0;right: 0;bottom: 0;margin: auto;z-index: 2;

  width: 3em;height: 20px;line-height: 20px;text-align: center;

  background: rgba(0, 0, 0, .7);color: #fff;border-radius: 20px;

  opacity: 0;

  transition: opacity 0.1s ease-out;

}

.photoview-view{

  position: absolute;

  cursor: all-scroll;

  background-repeat: no-repeat;

  background-position: 50% 50%;

  background-size: 100% 100%;

  box-shadow: 0 5px 25px 0 rgba(0, 0, 0, 0.4);

  transition: width 0.3s ease-out, 

    height 0.3s ease-out, 

    left 0.3s ease-out, 

    top 0.3s ease-out;

}

.photoview-close{position: absolute;right: 10px;top: 10px;color: #fff;cursor: pointer;}

.photoview-control{

  position: absolute;left: 0;right: 0;bottom: 0;height: 120px;

  background-color: rgba(0, 0, 0, .6);opacity: 0;

  transition: all 0.3s ease-out;

}

.photoview-control:hover{opacity: 1;}

.photoview-control-queue{

  position: absolute;left: 0;top: 15px;width: 10000%;height: 60px;

  transition: all 0.4s ease-out;

}

.photoview-control-queue p{

  display: inline-block;width: 60px;height: 60px;margin: 0 2px;background-color: rgba(0, 0, 0, .8);

  background-size: cover;cursor: pointer;

  transition: all 0.2s ease-out;

}

.photoview-control-queue p.active{

  opacity: 1;

}

.photoview-control-edit{

  position: absolute;left: 0;bottom: 15px;width: 100%;height: 15px;

  text-align: center;

}

.photoview-control-edit:before{

  content: "";position: absolute;left: 50%;top: -20px;width: 0;height: 0;margin-left: -10px;overflow: hidden;

  border: 10px solid transparent;border-bottom-color: rgba(255, 255, 255, .7);

}

.photoview-control-edit > div{

  display: inline-block;margin: 0 2px;width: 4em;min-width: 10px;min-height: 10px;

  cursor: pointer;color: #fff;text-align: center;

}

.photoview-scale-up:before{content: "放大";}

.photoview-scale-down:before{content: "缩小";}

.photoview-scale-adapt:before{content: "自适应";}

.photoview-prev:before{content: "上一张";}

.photoview-next:before{content: "下一张";}

.photoview-rotate-ccw:before{content: "逆时针";}

.photoview-rotate-cw:before{content: "顺时针";}

.photoview-download:before{content: "下载";}
View Code

 

demo

<!DOCTYPE html>

<html>

<head>

  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

  <title>图片浏览</title>

  <style>   

    .list img{float: left;display: block;width: 50px;height: 50px;margin: 2px;}

  </style>

</head>

<body>

  <div id="list" class="list">

    <img src="http://i1.tietuku.com/f424109042f29ed6.jpg" alt="">

    <img src="http://i3.tietuku.com/01585f07bf4308b6.jpg" alt="">

    <img src="http://i3.tietuku.com/dc295d3a37c11bbb.jpg" alt="">

    <img src="http://i3.tietuku.com/20bdc0bcd3e94334.jpg" alt="">

    <img src="http://i3.tietuku.com/a43fac13664dc8ee.jpg" alt="">

  </div>


<!-- 引入Photoview的css和js --> <link rel="stylesheet" href="./photoView.css"> <script src="./photoview.js"></script> <script> var pv=new PhotoView(), // 初始化PhotoView,生成DOM元素 list=document.querySelector("#list"); pv.add(list.children); // 将元素添加到PhotoView list.onclick=function (e) { e=window.event||e; var target=e.srcElement||e.target; // 事件委托 if(target.nodeName==="IMG"){ pv.show(); // 显示PhotoView } var index=getIndex(target); pv.aim(index); // 定位到某个图片 }; list.children[0].click(); /** * 获取当前元素在兄弟元素中的index * @param {dom} elem 目标元素 * @return {number} index */ function getIndex(elem) { if(elem.sourceIndex){ return elem.sourceIndex-elem.parentNode.sourceIndex; } else{ var i=0; while(elem=elem.previousElementSibling) i++; return i; } } </script> </body> </html>

 

你可能感兴趣的:(cas)