手机相册查看

 <!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
 <title>手势实现图像预览</title>
 <link rel="stylesheet" href="style_c0d0732.css">
 </head>
 <body>
 <div class="card">
 <div class="head">
 <div class="avatar">
 <img src="https://dn-lay.qbox.me/build/single-page/images/my-avatar_0b91c8c.jpg">
 </div>
 <div class="username">剧中人</div>
 <div class="time">今天15:34</div>
 </div>
 <div class="content">
 字不重要看图,对的,看图。
 </div>
 <div class="pics">
 <div class="item">
 <img src="imgs/me_thumb_206a0fd.jpg">
 </div>
 <div class="item">
 <img src="imgs/psb_thumb_e125261.jpg">
 </div>
 <div class="item">
 <img src="imgs/window_thumb_c99152e.jpg">
 </div>
 </div>
 <div class="comment">
 我也说一句
 </div>
 </div>
 <script type="text/tpl" id=tpl>
 <div class="swiper zoomIn">
 <div class="swiper-list">
 <div class="swiper-list-body">
 <div class="swiper-item"></div>
 <div class="swiper-item"></div>
 <div class="swiper-item"></div>
 </div>
 </div>
 <div class="swiper-num">
 <span class="current-index">1</span class="total-count">/<span>3</span>
 </div>
 <div class="swiper-menu">
 <div class="menu-pop">
 <div class="main-list">
 <a class="menu-item" href="javascript:void(0)">保存到手机</a>
 <a class="menu-item" href="javascript:void(0)">发送给 QQ 好友</a>
 <a class="menu-item" href="javascript:void(0)">发送给微信好友</a>
 <a class="menu-item" href="javascript:void(0)">收藏</a>
 </div>
 <div class="cancel">
 <a href="javascript:void(0)">取消</a>
 </div>
 </div>
 </div>
 </div>
 </script>
 <script src="js/toucher_2cb1d8f.js"></script>
 <script src="js/swipe_8158bb6.js"></script>
 <script type="text/javascript">
 (function(){
 var node_pics = document.getElementsByClassName('item'),
 big_pic_urls = [
 'imgs/me_ba1d3e6.jpg',
 'imgs/psb_da08ff5.jpeg',
 'imgs/window_e02f4ca.jpg'
 ];
 Array.prototype.forEach.call(node_pics,function(node,index){
 //监听点击事件
 new util.toucher(node).on('singleTap',function(){
 new swiper(big_pic_urls,index);
 });
 //偷偷加载图片
 new Image().src=big_pic_urls[index];
 });
  
 })();
 </script>
 </body>
 </html>
 
js1:

(function(global,doc,factoryFn){
	//初始化toucher主方法
	var factory = factoryFn(global,doc);

	//提供window.util.toucher()接口
	global.util = global.util || {};
	global.util.toucher = global.util.toucher || factory;

	//提供CommonJS规范的接口
	global.define && define(function(require,exports,module){
		return factory;
	});
})(this,document,function(window,document){
	/**
	 * 判断是否拥有某个class
	 */
	function hasClass(dom,classSingle){
		return dom.className.match(new RegExp('(\\s|^)' + classSingle +'(\\s|$)'));
	}

	/**
	 * @method 事件触发器
	 * @description 根据事件最原始被触发的target,逐级向上追溯事件绑定
	 *
	 * @param string 事件名
	 * @param object 原生事件对象
	 */
	function EMIT(eventName,e){
		this._events = this._events || {};
		//事件堆无该事件,结束触发
		if(!this._events[eventName]){
			return;
		}
		//记录尚未被执行掉的事件绑定
		var rest_events = this._events[eventName];

		//从事件源:target开始向上冒泡
		var target = e.target;
		while (1) {
			//若没有需要执行的事件,结束冒泡
			if(rest_events.length ==0){
				return;
			}
			//若已经冒泡至顶,检测顶级绑定,结束冒泡
			if(target == this.dom || !target){
				//遍历剩余所有事件绑定
				for(var i=0,total=rest_events.length;i<total;i++){
					var classStr = rest_events[i]['className'];
					var callback = rest_events[i]['fn'];
					//未指定事件委托,直接执行
					if(classStr == null){
						event_callback(eventName,callback,target,e);
					}
				}
				return;
			}

			//当前需要校验的事件集
			var eventsList = rest_events;
			//置空尚未执行掉的事件集
			rest_events = [];

			//遍历事件所有绑定
			for(var i=0,total=eventsList.length;i<total;i++){
				var classStr = eventsList[i]['className'];
				var callback = eventsList[i]['fn'];
				//符合事件委托,执行
				if(hasClass(target,classStr)){
					//返回false停止事件冒泡及后续事件,其余继续执行
					if(event_callback(eventName,callback,target,e) == false){
						return;
					}
				}else{
					//不符合执行条件,压回到尚未执行掉的列表中
					rest_events.push(eventsList[i]);
				}
			}
			//向上冒泡
			target = target.parentNode;
		}
	}

	/**
	 * 执行绑定的回调函数,并创建一个事件对象
	 * @param[string]事件名
	 * @param[function]被执行掉的函数
	 * @param[object]指向的dom
	 * @param[object]原生event对象
	 */
	function event_callback(name,fn,dom,e){
		//优先使用自定义的touches(目前是为了解决touchEnd无touches的问题)
		var touches = e.plugTouches || e.touches,
			touch = touches.length ? touches[0] : {},
			newE = {
				type : name,
				target : e.target,
				pageX : touch.pageX,
				pageY : touch.pageY
			};
		//为swipe事件增加交互初始位置及移动距离
		if(name.match(/^swipe/) && e.plugStartPosition){
			newE.startX = e.plugStartPosition.pageX;
			newE.startY = e.plugStartPosition.pageY;
			newE.moveX = newE.pageX - newE.startX;
			newE.moveY = newE.pageY - newE.startY;
		}
		//执行绑定事件的回调,并记录返回值
		var call_result = fn.call(dom,newE);
		//若返回false,阻止浏览器默认事件
		if(call_result == false){
			e.preventDefault();
			e.stopPropagation();
		}

		return call_result;
	}
	/**
	 * 判断swipe方向
	 */
	function swipeDirection(x1, x2, y1, y2) {
		return Math.abs(x1 - x2) >=	Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down');
	}

	/**
	 * 监听原生的事件,主动触发模拟事件
	 *
	 */
	function eventListener(DOM){
		var this_touch = this;

		//轻击开始时间
		var touchStartTime = 0;

		//记录上一次点击时间
		var lastTouchTime = 0;

		//记录初始轻击的位置
		var x1,y1,x2,y2;

		//轻击事件的延时器
		var touchDelay;

		//测试长按事件的延时器
		var longTap;

		//记录当前事件是否已为等待结束的状态
		var isActive = false;
		//记录有坐标信息的事件
		var eventMark = null;
		//单次用户操作结束
		function actionOver(e){
			isActive = false;
			clearTimeout(longTap);
			clearTimeout(touchDelay);
		}

		//断定此次事件为轻击事件
		function isSingleTap(){
			actionOver();
			EMIT.call(this_touch,'singleTap',eventMark);
		}
		//触屏开始
		function touchStart(e){
			//缓存事件
			eventMark = e;
			x1 = e.touches[0].pageX;
			y1 = e.touches[0].pageY;
			x2 = 0;
			y2 = 0;
			isActive = true;
			touchStartTime = new Date();
			EMIT.call(this_touch,'swipeStart',e);
			//检测是否为长按
			clearTimeout(longTap);
			longTap = setTimeout(function(){
				actionOver(e);
				//断定此次事件为长按事件
				EMIT.call(this_touch,'longTap',e);
			},500);
		}
		//触屏结束
		function touchend(e){
			//touchend中,拿不到坐标位置信息,故使用全局保存下数据
			e.plugStartPosition = eventMark.plugStartPosition;
			e.plugTouches = eventMark.touches;

			EMIT.call(this_touch,'swipeEnd',e);
			if(!isActive){
				return;
			}
			var now = new Date();
			//若未监听doubleTap,直接响应
			if(!this_touch._events.doubleTap || this_touch._events.doubleTap.length == 0){
				isSingleTap();
			}else if(now - lastTouchTime > 200){
				//延迟响应
				touchDelay = setTimeout(isSingleTap,190);
			}else{
				clearTimeout(touchDelay);
				actionOver(e);
				//断定此次事件为连续两次轻击事件
				EMIT.call(this_touch,'doubleTap',eventMark);
			}
			lastTouchTime = now;
		}

		//手指移动
		function touchmove(e){
			//缓存事件
			eventMark = e;
			//在原生事件基础上记录初始位置(为swipe事件增加参数传递)
			e.plugStartPosition = {
				pageX : x1,
				pageY : y1
			};
			//断定此次事件为移动事件
			EMIT.call(this_touch,'swipe',e);

			if(!isActive){
				return;
			}
			x2 = e.touches[0].pageX;
			y2 = e.touches[0].pageY;
			if(Math.abs(x1-x2)>2 || Math.abs(y1-y2)>2){
				//断定此次事件为移动手势
				var direction = swipeDirection(x1, x2, y1, y2);
				EMIT.call(this_touch,'swipe' + direction,e);
			}else{
				//断定此次事件为轻击事件
				isSingleTap();
			}
			actionOver(e);
		}

		/**
		 * 对开始手势的监听
		 */
		DOM.addEventListener('touchstart',touchStart);
		DOM.addEventListener('MSPointerDown',touchStart);
		DOM.addEventListener('pointerdown',touchStart);

		/**
		 * 对手势结束的监听(轻击)
		 */
		DOM.addEventListener('touchend',touchend);
		DOM.addEventListener('MSPointerUp',touchend);
		DOM.addEventListener('pointerup',touchend);

		/**
		 * 对移动手势的监听
		 */
		DOM.addEventListener('touchmove',touchmove);
		DOM.addEventListener('MSPointerMove',touchmove);
		DOM.addEventListener('pointermove',touchmove);

		/**
		 * 对移动结束的监听
		 */
		DOM.addEventListener('touchcancel',actionOver);
		DOM.addEventListener('MSPointerCancel',actionOver);
		DOM.addEventListener('pointercancel',actionOver);
	}

	/**
	 * touch类
	 *
	 */
	function Touch(DOM,param){
		var param = param || {};

		this.dom = DOM;
		//存储监听事件的回调
		this._events = {};
		//监听DOM原生事件
		eventListener.call(this,this.dom);
	}
	/**
	 * @method 增加事件监听
	 * @description 支持链式调用
	 *
	 * @param string 事件名
	 * @param [string] 事件委托至某个class(可选)
	 * @param function 符合条件的事件被触发时需要执行的回调函数
	 *
	 **/
	Touch.prototype.on = function ON(eventStr,a,b){
		var className,fn;
		if(typeof(a) == 'string'){
			className = a.replace(/^\./,'');
			fn = b;
		}else{
			className = null;
			fn = a;
		}
		//检测callback是否合法,事件名参数是否存在·
		if(typeof(fn) == 'function' && eventStr && eventStr.length){
			var eventNames = eventStr.split(/\s+/);
			for(var i=0,total=eventNames.length;i<total;i++){

				var eventName = eventNames[i];
				//事件堆无该事件,创建一个事件堆
				if(!this._events[eventName]){
					this._events[eventName] = [];
				}
				this._events[eventName].push({
					className : className,
					fn : fn
				});
			}
		}

		//提供链式调用的支持
		return this;
	};

	//对外提供接口
	return function (dom){
		return new Touch(dom);
	};
});
js2:

(function(){
  /**
   * 判断dom是否拥有某个class
  **/
  function hasClass(dom,classSingle){
    return dom.className && dom.className.match(new RegExp('(\\s|^)' + classSingle + '(\\s|$)')) || false;
  }
  function addClass(dom, cls) {
    if (!hasClass(dom, cls)) dom.className += " " + cls;
  }
  function removeClass(dom, cls) {
    if (hasClass(dom, cls)) {
      var reg = new RegExp('(\\s+|^)' + cls + '(\\s+|$)');
      dom.className = dom.className.replace(reg, ' ');
    }
  }
  function setCss(node,cssObj){
    for(var key in cssObj){
      node.style[key] = cssObj[key];
      if(key == 'transform' || key == 'transition'){
        node.style['-webkit-' + key] = cssObj[key];
      }
    }
  }
  function createDom(html){
    var a = document.createElement('div');
    a.innerHTML = html.replace(/^\s+|\s+$/g,'');
    return a.childNodes[0];
  }
  function removeNode(elem){
    if(elem && elem.parentNode && elem.tagName != 'BODY'){
      elem.parentNode.removeChild(elem);
    }
  }
  var tpl = document.getElementById('tpl').innerHTML,
      body = document.getElementsByTagName('body')[0];
  function swiper(pics,index){
    var me = this,
        touch;
    me.node = createDom(tpl);
    me.swiper_list = me.node.getElementsByClassName('swiper-list')[0];
    me.swiper_list_body = me.node.getElementsByClassName('swiper-list-body')[0];
    me.swiper_items = me.swiper_list.getElementsByClassName('swiper-item');
    me.current_index = me.node.getElementsByClassName('current-index')[0];

    body.appendChild(me.node);
    me.index = index || 0;
    me.width = me.getWidth();
    me.total = me.swiper_items.length;
    me.refresh();
    me.scrollToItem(me.index,false);
    Array.prototype.forEach.call(me.swiper_items,function(node,index){
      node.style['background-image'] = 'url(' + pics[index] + ')';
    });
    new util.toucher(me.node)
    .on('swipe',function(){
      return false;
    }).on('swipeLeft',function(){
      if(me.index + 1 >= me.total){
        me.shock('toLeft');
        return;
      }
      me.index++;
      me.scrollToItem(me.index,true);
    }).on('swipeRight',function(){
      if(me.index <= 0){
        me.shock('toRight');
        return
      }
      me.index--;
      me.scrollToItem(me.index,true);
    }).on('longTap',function(){
      me.showMenu();
      return false;
    }).on('singleTap',function(){
      me.destroy();
    })
    //重置 pop 手势
    .on('singleTap','.swiper-menu',function(){
      me.closeMenu();
      return false;
    }).on('swipeLeft','.swiper-menu',function(){
      return false;
    }).on('swipeRight','.swiper-menu',function(){
      return false;
    }).on('longTap','.swiper-menu',function(){
      return false;
    }).on('singleTap','.menu-item',function(){
      return false;
    });

    this.node.οncοntextmenu=function(){
      return false;
    }
  }
  swiper.prototype.destroy = function(){
    var me = this;
    removeClass(me.node,'zoomIn');
    addClass(me.node,'zoomOut');
    setTimeout(function(){
      removeNode(me.node);
    },400);
  }
  swiper.prototype.getWidth = function(){
    return this.node.clientWidth;
  }
  swiper.prototype.showMenu = function(){
    addClass(this.node,'showMenu');
  }
  swiper.prototype.closeMenu = function(){
    removeClass(this.node,'showMenu');
  }
  swiper.prototype.refresh = function(){
    var width = this.width;
    this.swiper_list_body.style.width = this.total * this.width + 'px';
    Array.prototype.forEach.call(this.swiper_items,function(node,index){
      node.style.width = width + 'px'
    });
  };
  swiper.prototype.shock = function(direction){
    var me = this,
        left = -me.index * me.width,
        a = direction=='toLeft' ? -40 : 40;
    me.scrollTo(left + a,true);
    setTimeout(function(){
      me.scrollTo(left,true);
    },200);
  };
  swiper.prototype.scrollToItem = function(index,useAnimation){
    this.current_index.innerHTML = index + 1;
    this.scrollTo(-index * this.width,useAnimation);
  };
  swiper.prototype.scrollTo = function(left,useAnimation){
    var useAnimation = typeof(useAnimation) == 'boolean' ? useAnimation : false,
        cssObj = {
          left: left + 'px'
        };

    cssObj.transition = useAnimation ? '.3s ease-in-out' : '0';
    setCss(this.swiper_list_body,cssObj);
  };
  window.swiper = swiper;
})();
css:
* {
  margin: 0;
  padding: 0;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
body {
  background: #fff;
  overflow: hidden;
}
.card {
  margin-top: 30px;
  background: #fff;
  border: 1px solid #ddd;
  border-width: 24px 0;
}
.card .head {
  height: 50px;
  padding: 15px;
}
.card .head .avatar {
  float: left;
  width: 50px;
  height: 50px;
  margin-right: 15px;
  border-radius: 50%;
  overflow: hidden;
  background: #eee;
}
.card .head .avatar img {
  display: block;
  width: 100%;
  height: 100%;
}
.card .head .username {
  line-height: 30px;
  font-size: 18px;
  color: #000;
}
.card .head .time {
  line-height: 15px;
  font-size: 13px;
  color: #aaa;
}
.card .content {
  padding: 10px 15px 20px;
  color: #000;
  font-size: 16px;
}
.card .pics {
  margin: 0 15px 20px;
  overflow: hidden;
  font-size: 0;
}
.card .pics .item {
  display: inline-block;
  width: 33.333333%;
  overflow: hidden;
  background: #333;
}
.card .pics .item::before {
  content: '';
  display: block;
  width: 100%;
  padding-top: 100%;
}
.card .pics .item img {
  display: block;
  width: 100%;
  margin-top: -100%;
}
.card .comment {
  height: 25px;
  border: 1px solid #eee;
  margin: 0 15px 20px;
  text-indent: 10px;
  line-height: 25px;
  font-size: 12px;
  color: #ccc;
}
.swiper {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background: #000;
  overflow: hidden;
}
.swiper-list {
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.swiper-list-body {
  position: absolute;
  width: 300%;
  height: 100%;
  top: 0;
  left: 0;
}
.swiper-item {
  position: relative;
  float: left;
  width: 33.33333%;
  height: 100%;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.swiper-num {
  position: absolute;
  bottom: 50px;
  left: 50%;
  width: 100px;
  margin-left: -50px;
  text-align: center;
  font-size: 14px;
  color: #fff;
}
.swiper-menu {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 100%;
  left: 0;
  transition: 0.3s ease-in-out;
  -webkit-transition: 0.3s ease-in-out;
}
.showMenu .swiper-menu {
  top: 0;
}
.menu-pop {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
}
.menu-pop .main-list,
.menu-pop .cancel {
  margin: 0 5px 5px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 0 1px rgba(0, 0, 0, 0.5);
}
.menu-pop a {
  display: block;
  line-height: 40px;
  text-align: center;
  text-decoration: none;
  font-size: 14px;
}
.menu-pop a + a {
  border-top: 1px solid #ccc;
}
@-webkit-keyframes zoomIn {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.6, 0.6, 0.6);
    transform: scale3d(0.6, 0.6, 0.6);
  }
  50% {
    opacity: 1;
  }
  to {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}
@keyframes zoomIn {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.6, 0.6, 0.6);
    transform: scale3d(0.6, 0.6, 0.6);
  }
  50% {
    opacity: 1;
  }
  to {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}
@-webkit-keyframes zoomOut {
  from {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
  20% {
    opacity: 1;
  }
  to {
    opacity: 0;
    -webkit-transform: scale3d(0.6, 0.6, 0.6);
    transform: scale3d(0.6, 0.6, 0.6);
  }
}
@keyframes zoomOut {
  from {
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
  20% {
    opacity: 1;
  }
  to {
    opacity: 0;
    -webkit-transform: scale3d(0.6, 0.6, 0.6);
    transform: scale3d(0.6, 0.6, 0.6);
  }
}
.zoomIn {
  -webkit-animation: zoomIn 0.3s ease-in-out forwards;
  animation: zoomIn 0.3s ease-in-out forwards;
}
.zoomOut {
  -webkit-animation: zoomOut 0.2s ease-in-out forwards;
  animation: zoomOut 0.2s ease-in-out forwards;
}

 
原文:http://bh-lay.github.io/toucher/swiper/ 


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值