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

这是项目开始前的基础

目录

  • 无缝滑屏(轮播图)
    • 基本布局
    • 基本滑屏逻辑
      • index为图片的索引
      • index为ul的位置
      • 定位版(开始加入小圆点)
      • 2D版
      • css组件
      • 2D版 --> 2D组件版
      • 2D组件版 --> 2D无缝组件版
      • 自动轮播
      • 无缝自动轮播组件
  • 复习1
  • -------------项目实战开始--------------
  • 头部
    • 骨架搭建
    • 头部布局
    • 头部遮罩
      • 布局
      • 遮罩js
  • 可拖拽导航
    • 布局 + 滑屏
    • 橡皮筋js
  • 复习2

无缝滑屏(轮播图)

基本布局

这是最基本的布局

<!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+='
  • +arr[i]+'"/>
  • '
    ; } //动态定义宽度 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+='
  • +arr[i]+'"/>
  • '
    ; } 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 += ''; }else{ pointsWrap.innerHTML += ''; } } //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+='
  • +arr[i]+'"/>
  • '
    ; } 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 += ''; }else{ pointsWrap.innerHTML += ''; } } 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+='
  • +arr[i]+'"/>
  • '
    ; } 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+=''; }else{ pointsWrap.innerHTML+=''; } } 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文件的过程这里就省略。

    效果图如下所示:
    尚硅谷_HTML5 移动端 项目实战 笔记(未完)_第1张图片

    头部

    头部产品规格
    
    ###总的设计图宽为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
    		文本居中
    

    面包屑导航:
    在这里插入图片描述
    遮罩层:
    尚硅谷_HTML5 移动端 项目实战 笔记(未完)_第2张图片

    骨架搭建

    /* 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>
    

    效果如下图所示:
    尚硅谷_HTML5 移动端 项目实战 笔记(未完)_第3张图片

    头部布局

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

    //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>
    

    头部遮罩

    效果如下图所示:
    尚硅谷_HTML5 移动端 项目实战 笔记(未完)_第4张图片
    尚硅谷_HTML5 移动端 项目实战 笔记(未完)_第5张图片

    布局

    // 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{
    		规则集
    	}
    

    你可能感兴趣的:(前端,H5)