码迷,mamicode.com
首页 > Web开发 > 详细

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

时间:2015-07-05 16:30:09      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:

 

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

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

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

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

 

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

 

    效果图:

技术分享

 

    代码如下:

 

js

技术分享
/**
 * 照片浏览
 * --
 * @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

技术分享
.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>

 

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

标签:

原文地址:http://www.cnblogs.com/lianer/p/4622217.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!