尚硅谷_HTML5 移动端 项目实战 笔记(未完)

这是项目开始前的基础

无缝滑屏(轮播图)

基本布局

这是最基本的布局

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
		<title></title>
		<style type="text/css">
			*{margin: 0;padding: 0;}		
			html,body{height: 100%;overflow: hidden;}
			#wrap{height: 100%;overflow: hidden;}
			.carousel-wrap > .list{list-style: none;}/*清除列表的默认样式*/
			.carousel-wrap > .list > li > a,
			.carousel-wrap > .list > li > a >img{display: block;}/*清除空隙*/
			.carousel-wrap > .list > li > a >img{width: 100%;}/*宽度自适应*/
			.carousel-wrap > .list > li{float: left;width: 20%;}/*width拿的是list的1/5,即20%*/
			.carousel-wrap > .list{width: 500%;overflow: hidden;}/*500%为li的5张图浮动后的宽度;overflow: hidden;使清除浮动撑开高度*/
		</style>
	</head>
	<body>
		<div id="wrap">
			<div class="carousel-wrap">
				<ul class="list">
					<li>
						<a href="javascript:;">
							<img src="img/01.jpg"/>
						</a>
					</li>
					<li>
						<a href="javascript:;">
							<img src="img/02.jpg"/>
						</a>
					</li>
					<li>
						<a href="javascript:;">
							<img src="img/03.jpg"/>
						</a>
					</li>
					<li>
						<a href="javascript:;">
							<img src="img/04.jpg"/>
						</a>
					</li>
					<li>
						<a href="javascript:;">
							<img src="img/05.jpg"/>
						</a>
					</li>
				</ul>
			</div>
		</div>
	</body>
	<script type="text/javascript">
		window.onload=function(){
			/*阻止默认行为*/
			document.addEventListener("touchstart",function(ev){
				ev=ev||event;
				ev.preventDefault();
			});
		}
	</script>
</html>

但这样的布局不够动态,满足不了我们的要求。
因此改为以下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
		<title></title>
		<style type="text/css">
			*{margin: 0;padding: 0;}
			html,body{height: 100%;overflow: hidden;}
			#wrap{height: 100%;overflow: hidden;}
			.carousel-wrap > .list{list-style: none;overflow: hidden;position: absolute;}/*定位后,carousel-wrap高度就为0,需要手动计算*/
			.carousel-wrap > .list > li{float: left;}
			.carousel-wrap > .list > li > a,.carousel-wrap > .list > li > a >img{display: block;}
			.carousel-wrap > .list > li > a >img{width: 100%;}
		</style>
	</head>
	<body>
		<div id="wrap">
			<!-- carousel-wrap为“包裹器” -->
			<div class="carousel-wrap"></div>
		</div>
	</body>
	<script type="text/javascript">
		window.onload=function(){
			/*阻止默认行为*/
			document.addEventListener("touchstart",function(ev){
				ev=ev||event;
				ev.preventDefault();
			});
			
			var arr=["img/01.jpg","img/02.jpg","img/03.jpg","img/04.jpg","img/05.jpg"];//图片
			
			carousel(arr);//调用函数
			function carousel(arr){
				var carouselWrap = document.querySelector(".carousel-wrap");//查看是否有“包裹器”
				if(carouselWrap){//如果有“包裹器”
					var ulNode = document.createElement("ul");//定义一个ul
					var styleNode = document.createElement("style");//创建一个style标签,用来添加生成的css样式
					ulNode.classList.add("list");//给定义的ul添加class(class="list")
					for(var i=0;i<arr.length;i++){//循环将图片加入html结构
						ulNode.innerHTML+='<li><a href="javascript:;"><img src="'+arr[i]+'"/></a></li>';
					}
					//动态定义宽度
					styleNode.innerHTML=".carousel-wrap > .list > li{width: "+(1/arr.length*100)+"%;}.carousel-wrap > .list{width: "+arr.length+"00%}";
					carouselWrap.appendChild(ulNode);//在html结构中加入ul
					document.head.appendChild(styleNode);//在结构中加入生成的css样式
					
					var imgNodes = document.querySelector(".carousel-wrap > .list > li > a >img");//获取图片
					setTimeout(function(){//初始时是没有结构的,获取时并没有渲染,因此需要延迟,等渲染完成后再取得
						carouselWrap.style.height=imgNodes.offsetHeight+"px";//carousel-wrap的高度为任意一张图片的高度即可
					},100)
				}
			}
			
		}
	</script>
</html>

基本滑屏逻辑

index为图片的索引

/*滑屏
  	1.拿到元素一开始的位置
  	2.拿到手指一开始点击的位置
  	3.拿到手指move的实时距离
  	4.将手指移动的距离加给元素
 */
					 
var startX = 0;//手指一开始的位置
var elementX = 0;//元素一开始的位置
var disX = 0;//手指滑动的距离
var index = 0;//图片的下标,不能定义在“touchend”函数的里面,因为如果定义在里面,则每次触发这个事件时,都会重新定义index且为0
carouselWrap.addEventListener("touchstart",function(ev){
	ev=ev||event;
	var TouchC = ev.changedTouches[0];//可能触屏的有多根手指,只拿其中的第一根
	startX = TouchC.clientX;//手指一开始的横坐标
	elementX = ulNode.offsetLeft;//元素的横坐标
})
carouselWrap.addEventListener("touchmove",function(ev){
	ev=ev||event;
	var TouchC = ev.changedTouches[0];//可能触屏的有多根手指,只拿其中的第一根
	var nowX = TouchC.clientX;//手指的实时位置
    disX = nowX - startX;//差值为实时距离
	ulNode.style.left = elementX+disX+"px";//手指拖动图片的位置 = 元素一开始的位置 + 手指滑动的距离
})
carouselWrap.addEventListener("touchend",function(ev){
	/* 向左/右滑动一点点,即可切换到右/左的图片 */
	ev=ev||event;
	if(disX>0){//disX>0表示向右滑
		index--;//向右滑
	}else if(disX<0){//disX>0表示向左滑
		index++;//向左滑
	}
	//图片滑动距离以一个视口的宽度为单位
	ulNode.style.left = -index*(document.documentElement.clientWidth)+"px";//index与图片的偏移是相反的
})

index为ul的位置

var startX = 0;
var elementX = 0;
carouselWrap.addEventListener("touchstart",function(ev){
	ev=ev||event;
	var TouchC = ev.changedTouches[0];
	startX = TouchC.clientX;
	elementX = ulNode.offsetLeft;
})
carouselWrap.addEventListener("touchmove",function(ev){
	ev=ev||event;
	var TouchC = ev.changedTouches[0];
	var nowX = TouchC.clientX;
    var disX = nowX - startX;//此时disX不用设在全局作用域
	ulNode.style.left = elementX+disX+"px";
})
carouselWrap.addEventListener("touchend",function(ev){
	ev=ev||event;
	//index抽象了ul的实时位置
	var index = ulNode.offsetLeft/document.documentElement.clientWidth;
	/* 此时,滑过图片的一半才会进行切换 */
	index = Math.round(index);//此时,index为小数;round()方法可把一个数字舍入为最接近的整数
	
//		/* 向左/右滑动一点点,即可切换到右/左的图片 */
//		//需要将disX定义在全局作用域
//		if(disX>0){
//			index = Math.ceil(index);//向上取整
//		}else if(disX<0){
//			index = Math.floor(index);//向下取整
//		}
	
	ulNode.style.left = index*(document.documentElement.clientWidth)+"px";//此时,不用再加负号
})

定位版(开始加入小圆点)

<div id="wrap">
	<div class="carousel-wrap">
		<!-- 下方的小圆点 -->
		<div class="points-wrap"></div>
	</div>
</div>

.carousel-wrap{position: relative;}/* 用于小圆点的绝对定位 */
/* 下方的小圆点 */
.carousel-wrap > .points-wrap{
	position: absolute;bottom: 0;
	width: 100%;text-align: center;/*居中*/
	z-index: 1;/*提升层级,使小圆点显示在图片的上面*/}
.carousel-wrap > .points-wrap > span{/* 每个小圆点 */
	display: inline-block;/*span默认为块级元素不能设置宽高*/
	width: 10px;height: 10px;border-radius: 50%;background: green;/*小圆点的样式*/
	margin-left:5px;/*小圆点之间的间隔*/}
.carousel-wrap > .points-wrap > span.active{background: deeppink;}/*选中状态的小圆点*/

<script type="text/javascript">
	window.onload=function(){
		document.addEventListener("touchstart",function(ev){
			ev=ev||event;
			ev.preventDefault();
		});
		
		var arr=["img/01.jpg","img/02.jpg","img/03.jpg","img/04.jpg","img/05.jpg"];
		
		carousel(arr);
		function carousel(arr){
			//布局
			var carouselWrap = document.querySelector(".carousel-wrap");
			if(carouselWrap){
				var ulNode = document.createElement("ul");
				var styleNode = document.createElement("style");
				ulNode.classList.add("list");
				for(var i=0;i<arr.length;i++){
					ulNode.innerHTML+='<li><a href="javascript:;"><img src="'+arr[i]+'"/></a></li>';
				}
				styleNode.innerHTML=".carousel-wrap > .list > li{width: "+(1/arr.length*100)+"%;}.carousel-wrap > .list{width: "+arr.length+"00%}";
				carouselWrap.appendChild(ulNode);
				document.head.appendChild(styleNode);
				
				var imgNodes = document.querySelector(".carousel-wrap > .list > li > a >img");
				setTimeout(function(){
					carouselWrap.style.height=imgNodes.offsetHeight+"px";
				},100)
				
				/* 下方的小圆点 */
				var pointsWrap = document.querySelector(".carousel-wrap > .points-wrap");//取得相应的html结构
				if(pointsWrap){//有小圆点这一结构,才表明需要这一功能
					for(var i=0; i<arr.length; i++){/*小圆点的html结构*/
						if(i==0){/*默认第一个小圆点为选中状态*/
							pointsWrap.innerHTML += '<span class="active"></span>';
						}else{
							pointsWrap.innerHTML += '<span></span>';
						}
					}
					//querySelectorAll的坑,只有结构已经生成,才能取得相应的结构
					var pointsSpan = document.querySelectorAll(".carousel-wrap > .points-wrap > span");//取得所有的小圆点
				}

				var startX = 0;
				var elementX = 0;
				carouselWrap.addEventListener("touchstart",function(ev){
					ev = ev||event;
					var TouchC = ev.changedTouches[0];
					
					ulNode.style.transition = "none";//刚开始时,清除transition过渡动画
					
					startX = TouchC.clientX;
					elementX = ulNode.offsetLeft;
				})
				carouselWrap.addEventListener("touchmove",function(ev){
					ev = ev||event;
					var TouchC = ev.changedTouches[0];
					var nowX = TouchC.clientX;
				    var disX = nowX - startX;
					ulNode.style.left = elementX+disX+"px";
				})
				carouselWrap.addEventListener("touchend",function(ev){
					ev = ev||event;
					//index抽象了ul的实时位置
					var index = ulNode.offsetLeft/document.documentElement.clientWidth;
					index = Math.round(index);
					
					/* 超出控制 */
					if(index>0){
						index = 0;
					}else if(index<1-arr.length){
						index = 1-arr.length;
					}
					//处理后的index可以代表小圆点的位置,只是符号相反
					
					for(var i=0;i<pointsSpan.length;i++){
						pointsSpan[i].classList.remove("active");//小圆点去除选中状态,以重新定义哪一个为选中状态
					}
					pointsSpan[-index].classList.add("active");
					
					ulNode.style.transition = ".5s left";//css的过渡动画
					ulNode.style.left = index*(document.documentElement.clientWidth)+"px";
				})
			}
		}
		
	}
</script>

2D版

transform造成的位移最终是不会影响offsetLeft的,因为两者不在同一图层上。因此,有offsetLeft的地方,都需要修改,之前offsetLeft都在帮我们计算实时的偏移量,现在修改之后,我们则需要自己主动进行记录和同步。

<script type="text/javascript">
	window.onload=function(){
		document.addEventListener("touchstart",function(ev){
			ev=ev||event;
			ev.preventDefault();
		});
		
		var arr=["img/01.jpg","img/02.jpg","img/03.jpg","img/04.jpg","img/05.jpg"];
		
		carousel(arr);
		function carousel(arr){
			var carouselWrap = document.querySelector(".carousel-wrap");
			if(carouselWrap){
				var ulNode = document.createElement("ul");
				var styleNode = document.createElement("style");
				ulNode.classList.add("list");
				for(var i=0;i<arr.length;i++){
					ulNode.innerHTML+='<li><a href="javascript:;"><img src="'+arr[i]+'"/></a></li>';
				}
				styleNode.innerHTML=".carousel-wrap > .list > li{width: "+(1/arr.length*100)+"%;}.carousel-wrap > .list{width: "+arr.length+"00%}";
				carouselWrap.appendChild(ulNode);
				document.head.appendChild(styleNode);
				
				var imgNodes = document.querySelector(".carousel-wrap > .list > li > a >img");
				setTimeout(function(){
					carouselWrap.style.height=imgNodes.offsetHeight+"px";
				},100)
				
				var pointsWrap = document.querySelector(".carousel-wrap > .points-wrap");
				if(pointsWrap){
					for(var i=0; i<arr.length; i++){
						if(i==0){
							pointsWrap.innerHTML += '<span class="active"></span>';
						}else{
							pointsWrap.innerHTML += '<span></span>';
						}
					}
					var pointsSpan = document.querySelectorAll(".carousel-wrap > .points-wrap > span");//取得所有的小圆点
				}
	
				var startX = 0;
				var elementX = 0;
				var translateX = 0;//用来记录实时的偏移量
				carouselWrap.addEventListener("touchstart",function(ev){
					ev = ev||event;
					var TouchC = ev.changedTouches[0];
					
					ulNode.style.transition = "none";
					
					startX = TouchC.clientX;
					//elementX = ulNode.offsetLeft;
					elementX = translateX;
				})
				carouselWrap.addEventListener("touchmove",function(ev){
					ev = ev||event;
					var TouchC = ev.changedTouches[0];
					var nowX = TouchC.clientX;
				  var disX = nowX - startX;
				  //var left = elementX + disX;
				  translateX = elementX + disX;
					//ulNode.style.left = elementX+disX+"px";
					ulNode.style.transform = 'translateX('+left+')';
				})
				carouselWrap.addEventListener("touchend",function(ev){
					ev = ev||event;
					//var index = ulNode.offsetLeft/document.documentElement.clientWidth;
					var index = translateX/document.documentElement.clientWidth;
					index = Math.round(index);
					
					if(index>0){
						index = 0;
					}else if(index<1-arr.length){
						index = 1-arr.length;
					}
					
					for(var i=0;i<pointsSpan.length;i++){
						pointsSpan[i].classList.remove("active");
					}
					pointsSpan[-index].classList.add("active");
					
					ulNode.style.transition = ".5s transform";
					//ulNode.style.left = index*(document.documentElement.clientWidth)+"px";
					translateX = index*(document.documentElement.clientWidth);
					ulNode.style.transition = 'translateX('+translateX+')';
				})
			}
		}
		
	}
</script>

可以发现,每一次改动translateX都需要进行相应的记录和同步,因此,我们需要构造一个函数来解决这个问题。

css组件

鉴于前面的问题,我们想要写一个函数来专门处理transform的读取

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style type="text/css">
			*{
				margin: 0;
				padding: 0;
			}
			
			#test{
				width: 100px;
				height: 100px;
				background: pink;
				/*transform:scale(2) translateX(100px);*/
			}
		</style>
	</head>
	<body>
		<div id="test"></div>
	</body>
	<script type="text/javascript">
		//css函数对transform的值进行读,写操作
		//css(node,type)  读
		//css(node,type,val)  写
		//规避覆盖的风险
		var test = document.querySelector("#test");
		css(test,"translateX",100);
		css(test,"translateX",200);
		css(test,"scale",2);
		console.log(css(test,"translateX"));//结果为:200
		
		/*
		   {
		  	translateX:val,
		    translateY:val,
		  	scale:val,
		  	rotate:val
		   }
		 */
		function css(node,type,val){
			if(typeof node === "object" && typeof node["transform"] === "undefined" ){
				node["transform"] = {};//如果没有这个属性,则添加;如果有,则覆盖
				//不能每次都覆盖,否则上一次的记录就没了
			}
			
			/*
			 	if(!node["transform"]){
			 		node["transform"] = {};
			 	}
			 		在这里,我们不能这么写,逻辑是相同的,但对于组件,需要较高的容错性
			 */
			
			if(arguments.length>=3){//如果参数大于等于3,则为写入操作
				var text = "";
				node["transform"][type] = val;//每次调用都可以将值塞入对象的属性中
				//拼串时一定要从对象中读取val的值,上面一行的val只是一次操作,拼串是要取决于对象的,因此我们要循环整个对象
				for(item in node["transform"]){//将属性一个一个地读出,进行字符串拼串(先写入的先读出)
					//hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性,如果为true,则为自身属性
					if(node["transform"].hasOwnProperty(item)){//判断是否是对象的直接属性,过滤掉原型链中的属性
						switch (item){//switch取出的是属性名
							//translateX和translateY放在一起
							case "translateX":
							case "translateY":
								text += item+"("+node["transform"][item]+"px)";
								break;
							case "scale":
								text += item+"("+node["transform"][item]+")";
								break;
							case "rotate":
								text += item+"("+node["transform"][item]+"deg)";
								break;
						}
					}
				}
				node.style.transform = node.style.webkitTransform = text;//兼容
			}else if(arguments.length==2){//如果参数等于2,则为读取操作
				val = node["transform"][type];//此时第三个参数已经不需要保留,但我们可以将其废物利用,而不用再定义一个新的变量
				if(typeof val === "undefined"){//设置默认值
					switch (type){
						case "translateX":
						case "translateY":
						case "rotate":
							val = 0;
							break;
						case "scale":
							val = 1;
							break;
					}
				}
				return val;
			}
		}		
	</script>
</html>

虽然我们已经写出了组件,但是我们需要将其提出,而不是直接写在网页中。
我们需要将其暴露以使用,我们将函数绑给window

/* js文件 */
+(function(w){
	w.css = function(node,type,val){...}
})(window)

此时,可以直接使用:
例如,

css(test."scale",2);

但是,如果我们再次定义css函数时,新定义的函数也是绑给window的,就会出现冲突
因此,我们采取以下方法,使用命名空间来解决命名冲突:

/* js文件 */
+(function(w){
	w.damu = {};
	w.damu.css = function(node,type,val){...}
})(window)
damu.css(test."scale",2);

2D版 --> 2D组件版

不再需要translateX,对象已经拥有其功能

var translateX =0;//不再需要

elementX = translateX;
//变为 elementX = damu.css(ulNode,"translateX");

translateX = elementX+disX;
ulNode.style.transform = 'translateX('+translateX+'px)';
//变为 damu.css(ulNode,"translateX",elementX+disX);

index = translateX/document.documentElement.clientWidth;
//变为 var index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;

translateX=index*(document.documentElement.clientWidth);
ulNode.style.transform ='translateX('+translateX+'px)';
//变为 damu.css(ulNode,"translateX",index*(document.documentElement.clientWidth));

2D组件版 --> 2D无缝组件版

我们我们采用再复制一组图片加在原图片的后面的方式

function carousel(arr){
	var carouselWrap = document.querySelector(".carousel-wrap");
	if(carouselWrap){
		var pointslength = arr.length;//定义一个变量,用于保存小圆点属性,因为复制一组图片后,arr.length为10
		arr = arr.concat(arr);//复制一组图片
		......
		if(pointsWrap){
			//将原来的arr.length改为pointslength
			for(var i=0;i<pointslength;i++){...}
		}
		......
		carouselWrap.addEventListener("touchend",function(ev){
			......
			//pointsSpan[-index].classList.add("active");
			//使小圆点的下标不会超出5
			pointsSpan[-index%pointslength].classList.add("active");
		})
	}
}

此时,第一张向右拉 / 最后一张向左拉 会出现空白
然后我们再来做成无缝的效果(即将空白替换为相应的图片,且让图片循环)

carouselWrap.addEventListener("touchstart",function(ev){
	......
	/* 无缝效果 */
	//点击第一组的第一张时,瞬间跳到第二组的第一张
	//点击第二组的最后一张时,瞬间跳到第一组的最后一张
	
	//获取当前的偏移量以判断当前是在哪一张图片,其正负与图片下标相反
	var index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;//index代表ul的位置
	if(-index === 0){//如果在第一张则跳到第二组的第一张
		index = -pointslength;//第二组的第一张
	}else if(-index ==(arr.length-1)){
		index = -(pointslength-1)//第二组的最后一张
	}
	damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);//进行相应的偏移
	......
}

但是有时我们是不需要无缝的,因此我们需要在有这一要求的时候才添加无缝效果。

<div class="carousel-wrap" needCarousel><!-- 在结构中添加needCarousel,如果存在则表示需要无缝效果 -->
	<div class="points-wrap"></div>
</div>

function carousel(arr){
	......
	/* 无缝效果 */
	var needCarousel = carouselWrap.getAttribute("needCarousel");
	needCarousel = needCarousel == null?false:true;//判断是否有needCarousel
	if(needCarousel){
		arr=arr.concat(arr);
	}
	
	......

	carouselWrap.addEventListener("touchstart",function(ev){
		......
		//点击第一组的第一张时,瞬间跳到第二组的第一张
		//点击第二组的最后一张时,瞬间跳到第一组的最后一张
		if(needCarousel){
			//获取当前的偏移量以判断当前是在哪一张图片,其正负与图片下标相反
			var index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;//index代表ul的位置
			if(-index === 0){//如果在第一张则跳到第二组的第一张
				index = -pointslength;//第二组的第一张
			}else if(-index ==(arr.length-1)){
				index = -(pointslength-1)//第二组的最后一张
			}
			damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);//进行相应的偏移
		}
		......
	})
}

自动轮播

function carousel(arr){
	......
	if(carouselWrap){
		carouselWrap.addEventListener("touchstart",function(ev){
			......
			//手动点击后,清除自动轮播
			clearInterval(timer);
		})

		carouselWrap.addEventListener("touchend",function(ev){
			......
			//手动操作完成后,恢复自动轮播
			auto();
		}

		/* 自动轮播 */
		var timer = 0;
		var autoFlag = 0;//抽象图片下标
		auto();
		function auto(){
			clearInterval(timer);
			timer=setInterval(function(){
				if(autoFlag == arr.length-1){
					ulNode.style.transition = "none";
					autoFlag = arr.length/2-1;
					damu.css(ulNode,"translateX",-autoFlag*document.documentElement.clientWidth);
				}
				setTimeout(function(){
					autoFlag++;
					ulNode.style.transition = "1s transform";
					xiaoyuandian(-autoFlag);
					damu.css(ulNode,"translateX",-autoFlag*document.documentElement.clientWidth);
				},50)
			},2000)
		}
		//小圆点
		function xiaoyuandian(index){
			if(!pointsWrap){
				return;
			}
			for(var i=0;i<pointsSpan.length;i++){
				pointsSpan[i].classList.remove("active");
			}
			pointsSpan[-index%pointslength].classList.add("active");
		}
	}
}

现在需要解决手动轮播后与自动轮播的同步问题。
index抽象的是ul位置,autoFlag抽象的是图片下标,
我们可以将这两个变量合为同一个,只需要加负号即可

var autoFlag = 0;//抽象图片下标
//替换后变为 var index = 0;

//将其放在前面的滑屏逻辑中定义:
/*滑屏
  	1.拿到元素一开始的位置
  	2.拿到手指一开始点击的位置
  	3.拿到手指move的实时距离
  	4.将手指移动的距离加给元素
  */
var index = 0;
var startX = 0;//手指一开始的位置
var elementX = 0;//元素一开始的位置
......

//"touchstart"中的var index不需要去掉var,因为那是用于无缝的,和自动/手动轮播的逻辑无关
//"touchend"中的var index需要去掉var,使其使用同一个index
//自动轮播逻辑中需要修改减数和被减数,以调整正负值
//加入needAuto相应的逻辑,用于判断是否需要添加自动轮播效果
<div class="carousel-wrap" needAuto><!-- 在结构中添加needAuto,如果存在则表示需要自动轮播效果 -->
	<div class="points-wrap"></div>
</div>

carouselWrap.addEventListener("touchend",function(ev){
	......
	//手动操作完成后,恢复自动轮播
	if(needAuto){
		auto();
	}
}

/* 自动轮播 */
var timer =0;
//判断是否需要自动轮播
var needAuto = carouselWrap.getAttribute("needAuto");
needAuto = needAuto == null?false:true;
if(needAuto){
	auto();
}
function auto(){
	clearInterval(timer);
	timer = setInterval(function(){
		if(index == 1-arr.length){
			ulNode.style.transition = "none";//清除过渡效果(第二组的最后一张回到第一组的第一张)
			index = 1-arr.length/2;
			damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);//相应的偏移
		}
		/*这里的定时器用于延迟,否则上面的“清除过渡效果”不产生作用
		    因为JS代码执行速度快,上面的“damu.css(...);”未渲染完成,就已经执行这个定时器中的代码*/
		setTimeout(function(){
			index--;
			ulNode.style.transition = "1s transform";//添加过渡
			xiaoyuandian(index);//小圆点
			damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);//相应的偏移
		},50)
	},2000)
}
//小圆点
function xiaoyuandian(index){
	if(!pointsWrap){
		return;
	}
	for(var i=0;i<pointsSpan.length;i++){
		pointsSpan[i].classList.remove("active");
	}
	pointsSpan[-index%pointslength].classList.add("active");
}

无缝自动轮播组件

现在,我们可以将逻辑代码抽出,作为一个组件

+(function(w){
	w.damu = {};
	w.damu.css=function (node,type,val){
		if(typeof node ==="object" && typeof node["transform"] ==="undefined" ){
			node["transform"]={};
		}
		
		if(arguments.length>=3){
			//设置
			var text ="";
			node["transform"][type] = val;
			
			for( item in node["transform"]){
				if(node["transform"].hasOwnProperty(item)){
					switch (item){
						case "translateX":
						case "translateY":
							text +=  item+"("+node["transform"][item]+"px)";
							break;
						case "scale":
							text +=  item+"("+node["transform"][item]+")";
							break;
						case "rotate":
							text +=  item+"("+node["transform"][item]+"deg)";
							break;
					}
				}
			}
			node.style.transform = node.style.webkitTransform = text;
		}else if(arguments.length==2){
			//读取
			val =node["transform"][type];
			if(typeof val === "undefined"){
				switch (type){
					case "translateX":
					case "translateY":
					case "rotate":
						val =0;
						break;
					case "scale":
						val =1;
						break;
				}
			}
			return val;
		}
	}
	w.damu.carousel=function (arr){
		//布局
		var carouselWrap = document.querySelector(".carousel-wrap");
		if(carouselWrap){
			var pointslength = arr.length;
			
			//无缝
			var needCarousel = carouselWrap.getAttribute("needCarousel");
			needCarousel = needCarousel == null?false:true;
			if(needCarousel){
				arr=arr.concat(arr);
			}
			
			var ulNode = document.createElement("ul");
			var styleNode = document.createElement("style");
			ulNode.classList.add("list");
			for(var i=0;i<arr.length;i++){
				ulNode.innerHTML+='<li><a href="javascript:;"><img src="'+arr[i]+'"/></a></li>';
			}
			styleNode.innerHTML=".carousel-wrap > .list > li{width: "+(1/arr.length*100)+"%;}.carousel-wrap > .list{width: "+arr.length+"00%}";
			carouselWrap.appendChild(ulNode);
			document.head.appendChild(styleNode);
			
			var imgNodes = document.querySelector(".carousel-wrap > .list > li > a >img");
			setTimeout(function(){
				carouselWrap.style.height=imgNodes.offsetHeight+"px";
			},100)
			
			var pointsWrap = document.querySelector(".carousel-wrap > .points-wrap");
			if(pointsWrap){
				for(var i=0;i<pointslength;i++){
					if(i==0){
						pointsWrap.innerHTML+='<span class="active"></span>';
					}else{
						pointsWrap.innerHTML+='<span></span>';
					}
				}
				var pointsSpan = document.querySelectorAll(".carousel-wrap > .points-wrap > span");
			}

			/*滑屏
			  	1.拿到元素一开始的位置
			  	2.拿到手指一开始点击的位置
			  	3.拿到手指move的实时距离
			  	4.将手指移动的距离加给元素
			  */
			var index =0;
			//手指一开始的位置
			var startX = 0;
			//元素一开始的位置
			var elementX = 0;
			//var translateX =0;
			carouselWrap.addEventListener("touchstart",function(ev){
				ev=ev||event;
				var TouchC = ev.changedTouches[0];
				ulNode.style.transition="none";
				
				//无缝
				/*点击第一组的第一张时 瞬间跳到第二组的第一张
				点击第二组的最后一张时  瞬间跳到第一组的最后一张*/
				//index代表ul的位置
				if(needCarousel){
					var index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;
					if(-index === 0){
						index = -pointslength;
					}else if(-index ==(arr.length-1)){
						index = -(pointslength-1)
					}
					damu.css(ulNode,"translateX",index*document.documentElement.clientWidth)
				}
				
				startX=TouchC.clientX;
				//elementX=ulNode.offsetLeft;
				//elementX=translateX;
				elementX=damu.css(ulNode,"translateX");
				
				//清楚定时器
				clearInterval(timer);
			})
			carouselWrap.addEventListener("touchmove",function(ev){
				ev=ev||event;
				var TouchC = ev.changedTouches[0];
				var nowX = TouchC.clientX;
			    var disX = nowX - startX;
			    
				//ulNode.style.left = elementX+disX+"px";
				
				/*translateX = elementX+disX;
				ulNode.style.transform = 'translateX('+translateX+'px)';*/
				damu.css(ulNode,"translateX",elementX+disX);
			})
			carouselWrap.addEventListener("touchend",function(ev){
				ev=ev||event;
				//index抽象了ul的实时位置
				//var index = ulNode.offsetLeft/document.documentElement.clientWidth;
				//var index = translateX/document.documentElement.clientWidth;
			    index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;
				index = Math.round(index);
				
				//超出控制
				if(index>0){
					index=0;
				}else if(index<1-arr.length){
					index=1-arr.length;
				}
				
				xiaoyuandian(index);
				
				ulNode.style.transition=".5s transform";
				//ulNode.style.left = index*(document.documentElement.clientWidth)+"px";
				/*translateX=index*(document.documentElement.clientWidth);
				ulNode.style.transform ='translateX('+translateX+'px)';*/
				damu.css(ulNode,"translateX",index*(document.documentElement.clientWidth));
				
				//开启自动轮播
				if(needAuto){
					auto();
				}
			})
		
			//自动轮播
			var timer =0;
			var needAuto = carouselWrap.getAttribute("needAuto");
			needAuto = needAuto == null?false:true;
			if(needAuto){
				auto();
			}
			function auto(){
				clearInterval(timer);
				timer=setInterval(function(){
					if(index == 1-arr.length){
						ulNode.style.transition="none";
						index = 1-arr.length/2;
						damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);
					}
					setTimeout(function(){
						index--;
						ulNode.style.transition="1s transform";
						xiaoyuandian(index);
						damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);
					},50)
				},2000)
			}
			
			function xiaoyuandian(index){
				if(!pointsWrap){
					return;
				}
				for(var i=0;i<pointsSpan.length;i++){
					pointsSpan[i].classList.remove("active");
				}
				pointsSpan[-index%pointslength].classList.add("active");
			}
		}
	}
})(window)

复习1

###复习1
	1.布局
		布局包裹器
		滑屏元素(动态生成)
			---queryselector的坑
			---有时绘制跟不上js引擎的渲染
					定时器
	2.基本的滑屏
		拿到元素和手指一开始(点击到布局包裹器上时)的位置
		拿到元素实时的位置,再去计算手指实时的偏移量,将偏移量实时的同步给滑屏元素
	
	3.
	  定位版(图片的下标    ul的位置)
		offsetLeft:累加的过程
	  2d变换版(单独的图层,影响最小)
		---变量(业务逻辑变得很复杂,因为变量只在对应的作用域中有效,属性更加的友好)
		---定义了css函数
			节点的属性来管理变换类型  他所对应的值
			2个参数
				读取
			3个参数
				设置(单位)
				循环节点的属性
	
	4.无缝 自动滑屏
		无缝:复制一组图片,当点击第一组第一张时瞬间跳到第二组的第一张
						      当点击第二组最后一张时瞬间跳到第一组的最后一张
		
		自动滑屏:循环定时器
					函数包裹(重启定时器)
						清定时器(循环定时器的逻辑没有必要同一时刻开启多次;暂停逻辑)

		自动滑屏和无缝的冲突
			使用同一个index变量就可以

-------------项目实战开始--------------

现在开始正式编写实战项目,项目采用less,编译为css文件的过程这里就省略。

效果图如下所示:
在这里插入图片描述

头部

头部产品规格

###总的设计图宽为1080

###06_音乐台项目
	整个页面背景色:#eee;
	
	头部上半部分高度:135
	
	logo部分:
		log 图片大小:240px * 88px
		log 左右内边距:17px
		            上内边距:26px
		            下内边距:21px
		            
	菜单按钮:
		菜单元素    129 * 135
		菜单按钮    雪碧图大小:82 * 233
		背景图偏移位置(关闭): center 16
		背景图偏移位置(开启): center -120
	
	按钮容器:
		上内边距   21
	
	登录/注册按钮:(注意内联元素,需要浮动)
		按钮大小: 111 * 78
		行高:78
		背景色 :  #690
		字体颜色: #ccc
		右外边距: 15px
		字体大小: 42
		文本居中
		圆角:8
	小搜索按钮:
		按钮大小: 130 * 88
		行高:88
		字体颜色: #fff
		右外边距: 30px
		上外边距: 3px
		字体加粗
		圆角:10
	------------------------------------------------
	搜索区:
		高	:103;
		上下左右内边距:16;
	
	输入框:(注意boxsizing!!!)
		宽(总): 829
		高(总): 103
		背景色: #999;
		上下内边距: 5
		左右内边距: 10
		边框: 1px solid #5a5a5a;(input输入框我们一般都会加1px边框)
		字体大小 : 41
		字体颜色: #333
		圆角:15
		
	大搜索按钮
		 宽: 203
  		 高: 103
  		 边框:清除边框
  		 背景颜色: #414040;
              	字体颜色: #fff;
      	         字体大小 : 41
      	        圆角: 15;
  	-------------------------------------------------
	定位层:
		宽度		 :100%
		绝对定位top : 135
		上下内边距	  : 10
		上边框: 1px solid #6a6a6a 
		背景颜色:rgba(0, 0, 0, .8)
	
	定位层元素:
		宽度	: 22.5%
		高度:135
		行高:135
		字体大小:54
		文本居中

面包屑导航:
在这里插入图片描述
遮罩层:
在这里插入图片描述

骨架搭建

/* tai.less */
*{
    margin: 0;
    padding: 0;
}
html,body{height: 100%;overflow: hidden;}

@rem: 1080/16rem;// 1rem值为多少位图像素
#wrap{
    height: 100%;
    overflow: hidden;//禁止系统默认滚动条
    .head{
        position: absolute;//模拟固定定位
        width: 100%;
        height: 100px;
        background: pink;
        .logo{
            img{
                width: 240/@rem;
            }
        }
    }
}
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0" />
		<title></title>
		<!-- 引用less编译后的css文件 -->
		<link rel="stylesheet" href="css/tai.css" />
	</head>
	<body>
		<div id="wrap">
			<div class="head">
				<div class="head-top">
					<h1 class="logo">
						<a href="http://www.atguigu.com">
							<img src="img/logo.png" />
						</a>
					</h1>
				</div>
			</div>
		</div>
	</body>
	<script type="text/javascript">
		window.onload=function(){
			/* 禁止系统默认行为 */
			document.addEventListener("touchstart",function(ev){
				ev=ev||event;
				ev.preventDefault();
			})
			
			/* rem适配 */
			;(function(){
				var styleNode = document.createElement("style");
				var w = document.documentElement.clientWidth/16;
				styleNode.innerHTML = "html{font-size"+w+"px!important}";
				document.head.appendChild(styleNode);
			})()
		}
	</script>
</html>

效果如下图所示:
在这里插入图片描述

头部布局

在移动端,能给高度就尽量给高度,这样可以避免字体过大的问题;此外,可以让整体布局确定下来,如果容器是靠内容撑开的,假如内容发生变化,则容器高度会发生变化,可能对布局产生影响。

//css reset
html,body,ul,li,h1,h2,h3,h4,span,div,p,a,form,input{margin: 0;padding: 0;font-family: helvetica;}
html,body{height: 100%;overflow: hidden;}
ul{list-style: none;}
a{text-decoration: none;display: block}
a,input,button{-webkit-tap-highlight-color: rgba(0,0,0,0);-webkit-appearance: none;outline: none;border: none;}
img{display: block}


//1rem值伪多少位图像素
@rem:1080/16rem;
@import "mixin/1-px";
 #wrap{
        font-size: 16/@rem;//进行重置,排除.btns中font-size的影响
        height: 100%;
        overflow: hidden;//隐藏滚动条
        background: #EEEEEE;//整体的背景色
        .head{
            position: absolute;
            width: 100%;
            height: 100px;
            background: #232323;//头部的背景色
            height: 270/@rem;//将头部布局高度定死
            .head-top{
                height: 135/@rem;
                .logo{//logo
                    float: left;
                    padding: 26/@rem 17/@rem 21/@rem 17/@rem;
                    img{
                        width:240/@rem;
                    }
                }
                .menuBtn{//面包屑导航(菜单按钮)
                    float: left;
                    width: 129/@rem;
                    height: 135/@rem;
                    background: url(../img/menuBtn.png) no-repeat;
                    background-size: 82/@rem 233/@rem;//指定背景图大小,否则按原图大小
                    background-position: center 16/@rem;
                    &.active{//点开后的关闭按钮图形,"&"表示当前元素
                        background-position: center -120/@rem;
                    }
                }
                .btns{//按钮排
                    padding-top: 21/@rem ;
                    float: right;
                    a{
                        float: left;
                        width: 111/@rem;
                        height: 78/@rem;
                        line-height: 78/@rem;
                        background: #690;
                        color: #ccc;
                        margin-right: 15/@rem;
                        font-size: 42/@rem;//需要在wrap中重置
                        text-align: center;
                        border-radius: 8/@rem ;
                        &.search{//既是a标签,也是search,这里的样式会覆盖上面a标签中的样式
                            width: 130/@rem;
                            height: 88/@rem;
                            line-height: 88/@rem;
                            color: #fff;
                            margin-right: 30/@rem;
                            margin-top: 3/@rem;
                            font-weight: bold;
                            border-radius: 10/@rem;
                        }
                    }
                    
                }
            }
            .head-bottom{//搜索栏
                height: 103/@rem;
                padding: 16/@rem;
                form{
                    height: 100%;
                    input[type='text']{
                        float: left;//将两个input同时浮动,可以进行对齐
                        box-sizing: border-box;
                        height: 103/@rem;
                        width: 829/@rem;
                        background: #999999;
                        padding: 5/@rem 10/@rem;
                        border: 1px solid #5a5a5a;
                        font-size: 41/@rem;
                        color: #333333;
                        border-radius: 15/@rem 0 0 15/@rem;
                        &::-webkit-input-placeholder{//处理提示的文字
                            color: #333333;
                        }
                        &:focus{//获取焦点时,改变背景色
                            background: white;
                        }
                    }
                    input[type='submit']{
                        float: right;
                        width: 203/@rem;
                        height: 103/@rem;
                        background: #414040;
                        color: #fff;
                        font-size: 41/@rem;
                        border-radius:0 15/@rem 15/@rem 0 ;
                    }
                }
            }
<body>
	<div id="wrap">
		<div class="head">
			<div class="head-top">
				<!--logo-->
				<h1 class="logo">
					<a href="http://www.atguigu.com">
						<img src="img/logo.png" />
					</a>
				</h1>
				<!--面包屑导航-->
				<a href="javascript:;" class="menuBtn"></a>
				<!--按钮排-->
				<div class="btns">
					<a href="javascript:;" class="search">搜索</a>
					<a href="javascript:;">登录</a>
					<a href="javascript:;">注册</a>
				</div>
			</div>
			<div class="head-bottom">
				<form  method="post">
					<input type="text" placeholder="请碰我一下" />
					<input type="submit" value="搜索"/>
				</form>
			</div>
		</div>
	</div>
</body>

头部遮罩

效果如下图所示:
在这里插入图片描述
在这里插入图片描述

布局

// 1物理像素
// 1-px.less
.1-px(@color){
    position: relative;
    &:before{
        position: absolute;
        content: "";
        display: block;
        top: 0;
        width: 100%;
        height: 1px;
        background: @color;
        @media (-webkit-device-pixel-ratio:2 ){
            transform: scaleY(.5);
        };//写两个是为了兼容
        @media (-webkit-device-pixel-ratio:3 ){
            transform: scaleY(.333333333333);
        }
    }
}
...
@import "mixin/1-px";//引入1物理像素相关的混合,mixin是只是路径
#wrap{
	...
	.head{
		...
		.mask{
            .1-px(deeppink);
            position: absolute;
            left: 0;
            top: 135/@rem;
            width: 100%;
            padding: 10/@rem 0;
            background: rgba(0, 0, 0, .8);
            display: none;//默认不显示
            & > li{
                width: 22.5%;
                height: 135/@rem;
                font-size: 54/@rem;
                line-height: 135/@rem;
                text-align: center; 
                float: left;   
                a{//每个按钮
                    color: white;
                }          
            }
        }
	}
}
<body>
	<div id="wrap">
		<div class="head">
			...
			<ul class="mask">
				<li>
					<a href="javascript">首页</a>
				</li>
				<li>
					<a href="javascript">MV</a>
				</li>
				<li>
					<a href="javascript">悦单</a>
				</li>
				<li>
					<a href="javascript">V</a>
				</li>
				<li>
					<a href="javascript">音乐</a>
				</li>
				<li>
					<a href="javascript">商城</a>
				</li>
				<li>
					<a href="javascript">节目</a>
				</li>
				<li>
					<a href="javascript">饭团</a>
				</li>
				<li>
					<a href="javascript">咨询</a>
				</li>
				<li>
					<a href="javascript">我的家</a>
				</li>
				<li>
					<a href="javascript">APP下载</a>
				</li>
				<li>
					<a href="javascript">热门应用</a>
				</li>
			</ul>
		</div>
	</div>
</body>	

遮罩js

/* tools.js */
//操作active,classlist兼容性不好,因此自定义一个组件
(function(w){
	w.tools = {};
	tools.addClass=function (node,className){
		var reg = new RegExp("\\b"+className+"\\b");
		if(!reg.test(node.className)){
			node.className += (" "+className); 
		}
	}
	
	tools.removeClass=function (node,className){
		if(node.className){
			var reg = new RegExp("\\b"+className+"\\b");
			var classes = node.className;
			node.className = classes.replace(reg,"");
			if(/^\s*$/g.test(node.className)){
				node.removeAttribute("class");
			}
		}else{
			node.removeAttribute("class");
		}
	}
})(window)
<script src="js/tools.js"></script>

<script type="text/javascript">
	window.onload=function(){
		document.addEventListener("touchstart",function(ev){
			ev=ev||event;
			ev.preventDefault();
		})
		
		;(function(){
			var styleNode = document.createElement("style");
			var w = document.documentElement.clientWidth/16;
			styleNode.innerHTML="html{font-size:"+w+"px!important}";
			document.head.appendChild(styleNode);				
		})()
		
		/* 搜索框的聚焦 */
		/* 因为阻止了默认行为,因此需要我们自己手动实现聚焦 */
		changeFocus()
		function changeFocus(){
			var inputText = document.querySelector("#wrap .head .head-bottom form input[type='text']");
			inputText.addEventListener("touchstart",function(ev){//聚焦
				ev = ev||event;
				this.focus();
				ev.stopPropagation();//阻止冒泡
				ev.preventDefault();//每次阻止冒泡后都需要再次禁止默认事件
			})
			document.addEventListener("touchstart",function(){//失焦
				inputText.blur();
			})
		}
		
		/* 面包屑导航的展开与关闭 */
		CMCFMenuBtn();
		function CMCFMenuBtn(){
			var menuBtn = document.querySelector("#wrap .head .head-top .menuBtn");
			var mask = document.querySelector("#wrap .head .mask");
			//isXX:false 频道按钮
			//isXX:ture	 XX按钮
			var isXX = false;//默认状态为关闭
			menuBtn.addEventListener("touchstart",function(ev){
				ev = ev||event;
				var touchC = ev.changedTouches[0];
				if(!isXX){/* 展开 */
					tools.addClass(menuBtn,"active");
					mask.style.display = "block";
				}else{/* 隐藏 */
					tools.removeClass(menuBtn,"active");
					mask.style.display = "none";
				}
				isXX = !isXX;
				
				/* menuBtn.addEventListener("touchstart" 和 document.addEventListener("touchstart"
			     因为事件冒泡,会造成冲突 */
			    
				ev.stopPropagation();//阻止冒泡
				ev.preventDefault();//每次阻止冒泡后都需要再次禁止默认事件
			})
   
			/* 点击其他部分时,关闭展开 */
			document.addEventListener("touchstart",function(){
				if(isXX){
					tools.removeClass(menuBtn,"active");
					mask.style.display = "none";
					isXX = !isXX;
				}
			})
			
			/* 点击遮罩的非跳转部位时,遮罩不应该消失 */
			mask.addEventListener("touchstart",function(ev){
				ev = ev||event;
				ev.stopPropagation();//阻止冒泡
				ev.preventDefault();//每次阻止冒泡后都需要再次禁止默认事件
			})
		}
	}
</script>

可拖拽导航

可拖拽导航产品规格

###总的设计图宽为1080

###06_音乐台项目
	整个内容区: 270px 的头部空隙
	
	导航: 高度+纵向padding+border 177(box-sizing)
			border: 1
			padding:上 31
					下 14
	
	导航元素: 高:129
			  左右内边距:38
			  
           默认字体颜色: #020202;
           选中时背景颜色: #690;
           选中时字体颜色: #fff;

布局 + 滑屏

这里需要修改1-px.less,添加位置参数,修改之后,之前的部分也需要相应的调整,这里就不再指出了。

/* 修改 1-px.less */
.1-px(top,@color:black){
    position: relative;
    &:before{
        position: absolute;
        content: "";
        display: block;
        top: 0;
        width: 100%;
        height: 1px;
        background: @color;
        @media (-webkit-device-pixel-ratio:2 ){
            transform: scaleY(.5);
        };
        @media (-webkit-device-pixel-ratio:3 ){
            transform: scaleY(.333333333333);
        }
    }
}
.1-px(bottom,@color:black){
    position: relative;
    &:before{
        position: absolute;
        content: "";
        display: block;
        bottom: 0;
        width: 100%;
        height: 1px;
        background: @color;
        @media (-webkit-device-pixel-ratio:2 ){
            transform: scaleY(.5);
        };
        @media (-webkit-device-pixel-ratio:3 ){
            transform: scaleY(.333333333333);
        }
    }
}
/* tai.less */
#wrap{
	position: relative;
	...
    .content{
       background: pink;
        //---内容占满除头部外的区域 
        position: absolute;
        top: 270/@rem;
        bottom: 0;
        left: 0;
        right: 0;
        //--------
        .nav{
            .1-px(bottom);//1像素的bottom边框
            width: 100%;//与布局视口一样宽
            height: 177/@rem;
            box-sizing: border-box;
            background: #EEEEEE;
            padding: 31/@rem 0 14/@rem 0;
            .list{
                //需要让li都在同一行
                //这里,每个li的宽度不同,因此无法使用轮播图的放大百分比宽度
                //也不能使用浮动,浮动时宽度不够会自动换行
                //这里使用父容器为white-space: nowrap;子元素为display: inline-block;
                
                font-size: 0;//display: inline-block;后元素间会有空隙,清除空隙
                white-space: nowrap;//不换行 
                //ul需要被撑开宽度,因为滑动处理时需要控制范围
                float: left;//这个浮动对自身没有影响,但使ul可以被li撑开宽度
                & > li{
                    height: 129/@rem;
                    line-height: 129/@rem;//居中
                    padding: 0 38/@rem;
                    font-size: 1rem;
                    display: inline-block;
                    a{
                        color: #020202;
                    }
                    &.active{//被选中状态
                        background: #690;
                        a{
                            color: #fff;
                        }
                    }
                }
            }
        }
    }
}
/* html */
<body>
	<div id="wrap">
		...
		<div class="content">
			<div class="nav"><!-- 滑屏区域 -->
				<ul class="list">
					<li class="active">
						<a href="javascript:;">首页</a>
					</li>
					<li>
						<a href="javascript:;">MV</a>
					</li>
					<li>
						<a href="javascript:;">悦单</a>
					</li>
					<li>
						<a href="javascript:;">V</a>
					</li>
					<li>
						<a href="javascript:;">音乐</a>
					</li>
					<li>
						<a href="javascript:;">商城</a>
					</li>
					<li>
						<a href="javascript:;">节目</a>
					</li>
					<li>
						<a href="javascript:;">饭团</a>
					</li>
					<li>
						<a href="javascript:;">咨询</a>
					</li>
					<li>
						<a href="javascript:;">我的家</a>
					</li>
					<li>
						<a href="javascript:;">APP下载</a>
					</li>
					<li>
						<a href="javascript:;">热门应用</a>
					</li>
					<li>
						<a href="javascript:;">晓飞张</a>
					</li>
					<li>
						<a href="javascript:;">金龙油</a>
					</li>
					<li>
						<a href="javascript:;">邱海峰</a>
					</li>
					<li>
						<a href="javascript:;">小贱贱</a>
					</li>
					<li>
						<a href="javascript:;"></a>
					</li>
				</ul>
			</div>
		</div>
	</div>
</body>
<script src="js/damu.js"></script><!-- 引入damu.js -->

/* 滑屏逻辑js */
drag();
function drag(){
	var wrap = document.querySelector("#wrap .content .nav");//滑屏区域
	var item = document.querySelector("#wrap .content .nav .list");//滑屏元素
	var startX=0;//元素一开始的位置
	var elementX =0;//手指一开始的位置
	
	wrap.addEventListener("touchstart",function(ev){
		ev = ev||event;
		var touchC = ev.changedTouches[0];
		
		startX = touchC.clientX;
		elementX = damu.css(item,"translateX");
	})
	
	wrap.addEventListener("touchmove",function(ev){
		ev = ev||event;
		var touchC = ev.changedTouches[0];
		var nowX = touchC.clientX;//手指的当前位置
		var disX = nowX - startX;//手指移动的距离
		damu.css(item,"translateX",elementX+disX);
	})
}

橡皮筋js

drag();
function drag(){
	...
	var minX = wrap.clientWidth - item.offsetWidth;//向右拉时产生的空隙距离

	wrap.addEventListener("touchstart",function(ev){
		...
		item.style.transition="none";//正常滑动时,清除"touchend"中的过渡效果
	})
	
	wrap.addEventListener("touchmove",function(ev){
		ev = ev||event;
		var touchC = ev.changedTouches[0];
		var nowX = touchC.clientX;//手指的当前位置
		var disX = nowX - startX;//手指移动的距离
		
		var translateX = elementX + disX;//手指一开始的位置 + 手指移动的距离
		
		/*橡皮筋效果
		 	在move的过程中,每一次touchmove真正的有效距离慢慢变小,元素的滑动距离还是在变大
		 */
		
		if(translateX > 0){//向右拉
			//var scale = 1-translateX/document.documentElement.clientWidth;//这样写比例最终会变为负值
			//scale范围为(0,1)
			//分母可以乘以一个数,此时分母越大,越难拉;例如分母*2,则scale范围为(0,.5)
			var scale = document.documentElement.clientWidth/((document.documentElement.clientWidth+translateX)*1.5);
			translateX = elementX + disX*scale;//一开始的位置 + 手指移动的距离*不断变小的比例
			//translateX=0;
		}else if(translateX < minX){//向左拉
			var over = minX - translateX;//不断向左拉动后,右边所产生的空隙距离
			var scale = document.documentElement.clientWidth/((document.documentElement.clientWidth+over)*1.5);
			translateX = elementX + disX*scale;
			//translateX = minX;
		}
		//因为进入判断才会产生橡皮筋效果,因此其中的变量不能提取出来放到外面
		//translateX = elementX + disX*scale;
		damu.css(item,"translateX",translateX);
	})

	/* 橡皮筋的反弹效果 */
	wrap.addEventListener("touchend",function(ev){
		var translateX = damu.css(item,"translateX");
		item.style.transition = "1s transform";//添加过渡效果
		if(translateX > 0){
			translateX = 0;
			damu.css(item,"translateX",translateX);
		}else if(translateX < minX){
			translateX = minX;
			damu.css(item,"translateX",translateX);
		}
	})
	
}

复习2

###复习2
	1.头部布局 效果
		---怎么使用less来弥补rem适配缺点
			定义了一个变量@rem(代表1rem包含多少位图像素)
		---表单
			表单高亮  outline:none
			表单内阴影	border:none
		---1物理像素的实现
			less 混合版
		---移动端骨架搭建
			meta标签
			挑选一个适配方案(百分比  rem适配 viewport适配)
			布局形式(流体+固定 275px )
			全面禁止事件默认行为的
			---js
				每次冒泡的时候,记住阻止事件的默认行为

	2.导航的布局  橡皮筋效果
		---导航 滑屏区域 与 滑屏元素的布局
			滑屏区域宽度必定占满一个视口
				滑屏区域宽度百分百
			滑屏元素必须被子项撑开
				滑屏元素必须浮动(为了能被子项撑开  禁止子项换行)
				子项统一inline-block
		---无缝滑屏 滑屏区域 与 滑屏元素的布局
			滑屏区域宽度必定占满一个视口
				滑屏区域宽度百分百
			滑屏元素必须被子项撑开
				width:子项个数*100%
				子项:1/子项个数 * 100%

###橡皮筋效果
	减少每次move的有效距离,最终的移动距离还是一直在增大
	move:每次手指移动的距离

###混合  继承
	.mixin(){
		规则集
	}
	
	#test{
		.mixin()
		//规则集
	}
	#test2{
		.mixin()
		//规则集
	}
	#test3{
		.mixin()
		//规则集
	}

	.extend{
		规则集
	}
	#test{
		&::extend(.extend)
	}
	#test1{
		&::extend(.extend)
	}
	#test2{
		&::extend(.extend)
	}
	
	#test,#test1,#test2{
		规则集
	}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值