IPHONE Swipe Effect with Photo Gallery

那么好吧,先大致分析下下面第一个链接的思路,不过按照我一贯的习惯,我会先简化代码,简化的文件有


iphone.css:


/* Basic Page Styling ********************************/
#wrapper {
	overflow: hidden;
	width: 250px;
	margin: 10px auto;
	border: 1px dotted #eee;
	background: #000;
	height: 400px;
	position: relative;
	}

#fake {
	overflow: hidden;
	width: 2000px;
	height: 400px;
	}
.content-box {
	float: left;
	width: 250px;
	height: 400px;
	display: block;
	}


/* Panel Style ***************************************/
.content-box {
	color: #d1d1d1;
	background: #000;
	}
.content-box .inner {margin: 16px;}

iphone.js:


var iPhoneAnimation = function()
{
	var initialPosition = null;
	var previousPosition = {};
	var direction = "";
	var width = parseInt($(".content-box:first").width(), 10);
	var thirdWidth = parseInt(width / 3, 10);
	
	return {
	
		init: function()
		{
			
		},
		moveInfo: function(e)
		{
			var $this = $(this);
			
			//Correct position in current box
			var position = e.pageX - $("#wrapper").offset().left;
			
			//Set our initial position, mouse movement now relates to this point
			if(initialPosition === null)
			{
				initialPosition = {left: position};
			}
			
			//Relative mouse point
			var mouseToPoint = initialPosition.left - position;
			
			//Check what direction mouse moved
			if(position > previousPosition.left)
			{
				direction = "right";
			} 
			else if(position < previousPosition.left)
			{
				direction = "left";
			}
			previousPosition = {left: position};
			
			//Move the current container to point
			$this.css({
				marginLeft: -mouseToPoint
			});
		},
		panelAnimate: function($this)
		{
			//Grab margin the panel was pulled too
			var margin = parseInt($this.css("marginLeft"), 10);
			
			//Look see if there is a previous / next element
			var $next = $this.next();
			var $prev = $this.prev();
			
			//Index used in indicators
			var index = $this.index();
			
			//User pulled left
			if(direction === "left")
			{
				//We have a next element to show
				if($next.length && margin < -thirdWidth)
				{
					$this.animate(
									{
										marginLeft: -width
									}, 
									550, 
									"easeOutCirc"
								);
					
				} 
				else 
				{
					//Spring back
					$this.animate(
									{
										marginLeft: 0
									}, 
									550, 
									"easeOutCirc"
								);
				}
			}
			
			//User pulled right
			if(direction === "right")
			{
				//We have a previous element to show
				if($prev.length && margin > thirdWidth)
				{
					$prev.animate(
										{
											marginLeft: 0
										}, 
										550, 
										"easeOutCirc", 
										function(){
											$this.css({
												marginLeft: 0
											});
										}
									);
					
				} 
				else 
				{
					//Spring back
					$this.animate({
						marginLeft: 0
					}, 550, "easeOutCirc");
				}
			}
		},
		
		resetVars: function()
		{
			initialPosition = null;
		}
	};
}();

jQuery(function($)
{
	//Initialise
	iPhoneAnimation.init();
	
	//Mouse down bind move event
	$(".content-box").bind(
		"mousedown", 
		function(e)
		{
			$(this).bind("mousemove", iPhoneAnimation.moveInfo);
		}
	);
	
	//Unbind mouse event
	$(".content-box").bind(
		"mouseup", 
		function(e)
		{
			var $this = $(this);
			
			$this.unbind("mousemove", iPhoneAnimation.moveInfo);
			//Animate the panel
			iPhoneAnimation.panelAnimate($this);
			//Reset the private var
			iPhoneAnimation.resetVars();
		}
	);
});

iphone-swipe


先来简单概述下HTML的结构:

<div id="wrapper">

	<div id="fake">

		<div id="c1" class="content-box">
			<div class="inner">
			
			</div>
		</div>

		<div id="c2" class="content-box">
			<div class="inner">


			</div>
		</div>

		<div id="c3" class="content-box">
			<div class="inner">
		

			</div>
		</div>

		<div id="c4" class="content-box">
			<div class="inner">


			</div>
		</div>

	</div><!-- div id="fake" -->

</div><!-- div id="wrapper" -->


一个叫wrapper的DIV扮演一个窗口的角色,或者说是mask,遮罩。只有它的范围以内的内容才会被显示出来,因为CSS里指定它的overflow属性为:hidden。

wrapper下面的直属子节点是fake,它其实是个容器,它装着四个被拖拽的类属性为content-box的DIV标签,每个DIV标签有自己的内容,wrapper的大小和每个content-box的大小完全相同,所以同一时刻,只有一个DIV出现。注意,至于这个拖拽的移动效果,是通过直接移动content-box实现的,不是fake,所以fake的overflow属性也是hidden。


下面看下js代码的思路:


首先是这个部分:

var iPhoneAnimation = function()
{
	var initialPosition = null;
	var previousPosition = {};
	var direction = "";
	var width = parseInt($(".content-box:first").width(), 10);
	var thirdWidth = parseInt(width / 3, 10);
	
	return {
	
		init: function()
		{
			
		},
		moveInfo: function(e)
		{
			
		},
		panelAnimate: function($this)
		{
			
		},
		
		resetVars: function()
		{
			
		}
	};
}();

简单看来,它声明了一个名为iPhoneAnimation的函数并即刻呼叫它,但实际上这是Javascript版本的类似高级语言的静态类做法,return前面声明的变量是它的静态成员,比如initialPosition,return区块中的函数则是静态方法,比如init。


至于第二段:

jQuery(function($)
{
	//Initialise
	iPhoneAnimation.init();
	
	//Mouse down bind move event
	$(".content-box").bind(
		
	);
	
	//Unbind mouse event
	$(".content-box").bind(
		
	);
});

这是利用jQuery,首先指定DOM加载后执行的动作,其中包括初始化静态类iPhoneAnimation,之后将content-box绑定两个事件,一个是mousedown,一个是mouseup。


在mousedown的处理函数中,将iPhoneAnimation的moveInfo方法绑定给content-box的mousemove事件。而在mouseup的处理函数中,将content-box的mousemove事件取消绑定,并执行panelAnimate方法和resetVars方法。


实际上moveInfo方法做的事情是更新一些静态类iPhoneAnimation的成员变量,还有将content-box根据鼠标位置移动,这样就做到了拖拽的感觉。而panelAnimate方法的任务则是根据成员变量将content-box按照逻辑完成下面的移动,也就是用户释放鼠标(或手指)后将被拖动的content-box弹回原地或弹出wrapper范围而将下一下content-box弹出来,这样就做到了所谓的类似Iphone的swipe效果。最后再通过resetVars方法重置iPhoneAnimation的成员变量来重置状态


在js代码中加入一些调试代码,追踪某些变量的变化:


moveInfo: function(e)
{
	var $this = $(this);
	
	console.log("the dragged div id: " + $this.attr('id'));
	
	//Correct position in current box
	var position = e.pageX - $("#wrapper").offset().left;
	
	if(initialPosition)
	{
		console.log("initialPosition.left before set: " + initialPosition.left);
	}
	
	
	//Set our initial position, mouse movement now relates to this point
	if(initialPosition === null)
	{
		initialPosition = {left: position};
	}
	
	console.log("initialPosition.left after set: " + initialPosition.left);
	
	//Relative mouse point
	var mouseToPoint = initialPosition.left - position;
	
	console.log("mouseToPoint: " + mouseToPoint);
	
	console.log("direction before set: " + direction);
	//Check what direction mouse moved
	if(position > previousPosition.left)
	{
		direction = "right";
	} 
	else if(position < previousPosition.left)
	{
		direction = "left";
	}
	
	console.log("direction after set: " + direction);
	
	
	console.log("previousPosition.left before set: " + previousPosition.left);
	
	previousPosition = {left: position};
	
	console.log("previousPosition.left after set: " + previousPosition.left);
	
	//Move the current container to point
	$this.css({
		marginLeft: -mouseToPoint
	});
},
panelAnimate: function($this)
{
	//Grab margin the panel was pulled too
	var margin = parseInt($this.css("marginLeft"), 10);
	
	//Look see if there is a previous / next element
	var $next = $this.next();
	var $prev = $this.prev();
	
	console.log("next: " + $next.attr('id'));
	console.log("prev: " + $prev.attr('id'));
	//Index used in indicators
	var index = $this.index();
	console.log("index: " + index);
	
	//User pulled left
	if(direction === "left")
	{
		//We have a next element to show
		if($next.length && margin < -thirdWidth)
		{
			$this.animate(
							{
								marginLeft: -width
							}, 
							550, 
							"easeOutCirc"
						);
			
		} 
		else 
		{
			//Spring back
			$this.animate(
							{
								marginLeft: 0
							}, 
							550, 
							"easeOutCirc"
						);
		}
	}
	
	//User pulled right
	if(direction === "right")
	{
		//We have a previous element to show
		if($prev.length && margin > thirdWidth)
		{
			$prev.animate(
								{
									marginLeft: 0
								}, 
								550, 
								"easeOutCirc", 
								function(){
									$this.css({
										marginLeft: 0
									});
								}
							);
			
		} 
		else 
		{
			//Spring back
			$this.animate({
				marginLeft: 0
			}, 550, "easeOutCirc");
		}
	}
},

然后,拖住第一个div,稍稍向左移动一点,输出的结果为:


the dragged div id: c1 
initialPosition.left after set: 148 
mouseToPoint: 0 
direction before set:
direction after set:  
previousPosition.left before set: undefined 
previousPosition.left after set: 148 

the dragged div id: c1 
initialPosition.left before set: 148 
initialPosition.left after set: 148 
mouseToPoint: 1 
direction before set:  
direction after set: left 
previousPosition.left before set: 148 
previousPosition.left after set: 147 

the dragged div id: c1 
initialPosition.left before set: 148 
initialPosition.left after set: 148 
mouseToPoint: 3 
direction before set: left 
direction after set: left 
previousPosition.left before set: 147 
previousPosition.left after set: 145 

the dragged div id: c1 
initialPosition.left before set: 148 
initialPosition.left after set: 148 
mouseToPoint: 6 
direction before set: left 
direction after set: left 
previousPosition.left before set: 145 
previousPosition.left after set: 142 


....


the dragged div id: c1 
initialPosition.left before set: 148 
initialPosition.left after set: 148 
mouseToPoint: 22 
direction before set: left 
direction after set: left 
previousPosition.left before set: 127 
previousPosition.left after set: 126 


next: c2 
prev: undefined 
index: 0 


在moveInfo()方法中,首先计算获得的是position,这个position是用鼠标事件的pageX减去wrapper的offset().left属性,前者是鼠标在整个页面的x坐标位置,后者是wrapper在页面的X轴偏移量,所以,由此得到的position其实是鼠标在wrapper内的本地x坐标,而wrapper是固定不变的,那么position的值就会因为朝着同一方向不停拖动鼠标而增加。就像观测数据中从148到126,鼠标的位移是向左22像素,于是被拖动的content-box的marginLeft属性就被设定为:-22。


现在来说说panelAnimate方法,当然这个方法首先要进行一些逻辑上的检测,比如位移是否超过了宽度的三分之一还有:向左移的话是否有上一个元素向右移的话是否有下一个元素等等。不过不论怎样,当被拖拽的concent-box将被弹回原位时,它的目标位置总是0:


//Spring back
$this.animate(
				{
					marginLeft: 0
				}, 
				550, 
				"easeOutCirc"
			);
即是说,当content-box被正常呈现时,它的x位置是0。而当要把它向左位移时,移动的是被拖拽者本身,它的目标位置是-width,就是-250,可是,当向右移动时,被用animate移动的是被拖拽者的前一个元素,由$prev指向的内容,它的目标位置是0。这同浏览器呈现HTML的原理有关,当你移动一个content-box向左时,它右边的内容会被浏览器自动呈现,然而反之却不行。所以使用这个程序当向左拖拽和向右拖拽时的效果是不同的,当向左时,后面的内容会自动跟进来,向右却不会。另外还请注意:

$prev.animate(
				{
					marginLeft: 0
				}, 
				550, 
				"easeOutCirc", 
				function(){
					$this.css({
						marginLeft: 0
					});
				}
			);

当将被拖拽的前一个元素的位移完成后,执行的动作是将被拖拽元素本身的x位置设置为0,这样它就会自动被放在当前显示的元素后面了。


Refs:

RECREATE IPHONE SWIPE EFFECT USING JQUERY
PhotoSwipe
Using the Swipe Gesture in Flash Using ActionScript 3.0


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值