尚硅谷_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");//定义一个ulvar 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结构中加入uldocument.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为10arr = arr.concat(arr);//复制一组图片......if(pointsWrap){//将原来的arr.length改为pointslengthfor(var i=0;i<pointslength;i++){...}}......carouselWrap.addEventListener("touchend",function(ev){......//pointsSpan[-index].classList.add("active");//使小圆点的下标不会超出5pointsSpan[-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;//判断是否有needCarouselif(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

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

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

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

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

    头部

    头部产品规格###总的设计图宽为1080###06_音乐台项目整个页面背景色:#eee;头部上半部分高度:135logo部分:log 图片大小:240px * 88pxlog 左右内边距: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{//logofloat: 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: 1padding:上 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

    ###复习21.头部布局 效果---怎么使用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{规则集}
    


    本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

    相关文章

    立即
    投稿

    微信公众账号

    微信扫一扫加关注

    返回
    顶部