我最近写了一个类似于京东详情的一个滑屏切换,这是应客户需求写的,切换效果做出来了,如果要达到京东那种效果还需要动画切换,目前我对js运动有点迷茫,所以就没有运动效果,如果你很擅长运动,可以添加上去,我就不写了,以后还会封装一个库,到时候会添加运动,知识总是越学越会的,相信不久的将来,自己会把js运动写的游刃有余,现如今就从最简单的做起吧。这个滑屏切换效果说小不小,内在还是挺丰富的,我不能保证自己写的代码多优美,因为我还没有到达写出优美的境界,我现在最多意义上算是个实现者,可以把程序功能给实现,我也很崇拜那些写出优美代码的牛人,他们是自己的目标。慢慢来,“路漫漫其修远兮,吾将上下而求索”
这个就是我从京东上截取的效果图,不过我要做的是这个
效果:当我们用手指滑动下面内容的时候,可以切换到下一屏幕内容,同时上面的标签也会滑动到相应的列表项上
原理:给每一个版块添加touch事件,让它每一次滑动一个屏幕,同时,获取每个屏幕的序号,给对应的标签加样式,同时让标签滚动,如何设置这些标签的滚动距离,由于标签文字大小不一,不可能固定滚动多少长度,所以我取标签最大滑动距离除以标签个数,就得到每个标签平均滑动距离,从而让标签页滑动
html代码结构部分
<!--标签项--> <nav class="nav bg1 pdl20 pdr20"> <div class="navInner"> <a href="" class="current">关于我们</a> <a href="">企业景愿</a> <a href="">招聘信息</a> <a href="">新闻中心</a> <a href="">招聘信息</a> </div> </nav>
内容项
<!--标签项--> <section class="seParent pdt66"> <ul class="seParentInner"> <li class="sectionWrap"> <section class="section bg1 pdl20 pdr20 mgb14 mgl20 mgr20 pdt20"> <ul class="news"> <li> <a href="" class="block"><img src="images/pic1.jpg" class="imgResponsive"/></a> <div class="newTxt"> <h4>标题标题标题标题标题标题</h4> <p>这里是内容这里是内容这里是内容这里是内容这里是内容 这里是内容这里是内容这里是内容这里是内容这里是内...</p> </div> </li> </ul> </section> <section class="section bg1 pdl20 pdr20 mgb14 mgl20 mgr20 pdt20"> <ul class="news"> <li> <a href="" class="block"><img src="images/pic1.jpg" class="imgResponsive"/></a> <div class="newTxt"> <h4>标题标题标题标题标题标题</h4> <p>这里是内容这里是内容这里是内容这里是内容这里是内容 这里是内容这里是内容这里是内容这里是内容这里是内...</p> </div> </li> </ul> </section> <section class="section bg1 pdl20 pdr20 mgb14 mgl20 mgr20 pdt20"> <ul class="news"> <li> <a href="" class="block"><img src="images/pic1.jpg" class="imgResponsive"/></a> <div class="newTxt"> <h4>标题标题标题标题标题标题</h4> <p>这里是内容这里是内容这里是内容这里是内容这里是内容 这里是内容这里是内容这里是内容这里是内容这里是内...</p> </div> </li> </ul> </section> </li><!--sectionWrap--> <li class="sectionWrap"> <article class="article bg1 pdl20 pdr20 mgb14 mgl20 mgr20 pdt20 pdb10"> <p>fdsfsdfsdf文字</p> <p>fdsfsdfsdf文字</p> <p>fdsfsdfsdf文字</p> </article> </li><!--sectionWrap--> <li class="sectionWrap"> <article class="article bg1 pdl20 pdr20 mgb14 mgl20 mgr20 pdt20 pdb10"> <p>fdsfsdfsdf文字</p> <p>fdsfsdfsdf文字</p> <p>fdsfsdfsdf文字</p> </article> </li> <li class="sectionWrap"> <article class="article bg1 pdl20 pdr20 mgb14 mgl20 mgr20 pdt20 pdb10"> <p>fdsfsdfsdf文字</p> <p>fdsfsdfsdf文字</p> <p>fdsfsdfsdf文字</p> </article> </li> <li class="sectionWrap"> <article class="article bg1 pdl20 pdr20 mgb14 mgl20 mgr20 pdt20 pdb10"> <p>fdsfsdfsdf文字</p> <p>fdsfsdfsdf文字</p> <p>fdsfsdfsdf文字</p> </article> </li> </ul><!--seParentInner--> </section><!--seParent-->
内容项的结构为什么如此设计:首先我需要知道这个最外层的父标签需要包裹ul列表的标签,ul中每个li就是一个屏幕,多个li就会是多个屏幕,最外层的标签overflow,就会让内层li只显示一屏幕且没有滚动条。
写完了结构,我们看样式,具体内容样式,我就不写了,太长了,且没有必要,我写整体框架的样式:
.seParent{overflow: hidden;}//这一句就是一次只显示一屏幕,不会有滚动条 .seParent .seParentInner{overflow: hidden;}//这一句至关重要,我写这个的时候,栽的坑就在这,写了这个,touchmove的时候就会正常touchmove .seParent .sectionWrap{float: left;}
接着我们看js部分
window.addEventListener('load',function(){ scroll({ parent:'.nav', child :'.navInner', li:'a', ancestor:'.seParent', content:'.seParentInner', con_child:'.sectionWrap', mr:0.6 }); });//这句页面装载结束,调用我们接下来写的滑屏切换函数
滑屏切换封装到一个函数中了,scroll,接下来我就一句一句分析,我也好重温一下当初的思路
function scroll(elem) { if(!elem){ return;//传进来的对象不存在突出 } if(!elem.mr){ elem.mr=0;//设置默认的mr值 } var oSection = document.querySelector(elem.parent);//获取nav的Dom对象 var oList = document.querySelector(elem.child);//获取navInner的Dom对象,这个对象将来要滑动作用 var oLi = oList.querySelectorAll(elem.li);//获取所有的a的Dom对象,这个用来计算整个navInner的宽度 var oAncestor = document.querySelector(elem.ancestor);//获取seParent的Dom对象 var oContent = document.querySelector(elem.content);//获取seParentInner的Dom对象,将来用来触发滑动事件 var oCon_child = oContent.querySelectorAll(elem.con_child);//获取每一个li的Dom对象 var html = parseFloat(document.documentElement.style.fontSize);//获取网页根元素大小,因为通篇是个手机站,运用flexible适配,所以要计算宽度 就要先获取整个html的fontSize大小,才会计算的精确。 var size = oLi.length;//获取每个a的个数 var count = oCon_child.length;//获取每个li的个数 var startEl = 0;//当前坐标水平位置移动的距离 var startElY =0;//当前坐标垂直位置移动距离 var startPoint;//当前横坐标位置 var startPointY;//当前纵坐标位置 var disX = 0;//水平移动的距离 var disY = 0;//垂直移动的距离 var target = 0;//水平目标位置距离 var targetY = 0;//纵向目标位置距离 var iWidth = 0;//.navInner标签的长度 var oConWidth = 100*count; var oConChildWidth = 100/count; var index = 0; var aWidth = oAncestor.offsetWidth; for(var i = 0;i<oLi.length;i++){ iWidth +=(oLi[i].offsetWidth+elem.mr*html); } oList.style.width=iWidth-20+'px';//设置整个navInner的宽度 for(var i = 0;i<oCon_child.length;i++){ oCon_child[i].style.width = oConChildWidth+'%';//设置每个li的宽度 } oContent.style.width = oConWidth+'%';//设置色parentInner的宽度 var maxTranslateX = Math.round(oSection.clientWidth-0.4*html) - Math.round(oList.offsetWidth);//获取navInner滑动的最大距离 var maxTranslateY = (document.documentElement.clientHeight-2.8*html)-oAncestor.offsetHeight;separent中得li内容向上滑动最大距离 var minTranslateY = 1.25*html;//设置最小向上滑动距离 maxTranslateX = maxTranslateX>0?0:maxTranslateX; oContent.style.height = oCon_child[index].offsetHeight+'px';//实时更新seParentInner的高度,这样做为了在不同大小内容的li向上滑动的时候,可 以实时获取最大的向上滑动距离。 oContent.addEventListener('touchstart',function(e){ startPoint = e.changedTouches[0].pageX;//获取按下坐标位置 startPointY = e.changedTouches[0].pageY; startEl = css(this,'translateX');//获取当前对象translatex值,这里调用了另一个js文件,获取translate的值的函数 startElY = css(this,'translateY'); index = Math.round(-startEl/aWidth);//这里获取手指按下时当前li是第几个li,因为startEl是赋值,所以要用负号 return false; }); oContent.addEventListener('touchmove',function(e){ e.preventDefault();//阻止浏览器默认事件,必须要有 var nowDis = e.changedTouches[0].pageX;//获取滑动坐标位置 var pageY = e.changedTouches[0].pageY; disX = nowDis-startPoint;//滑动坐标减去按下坐标获取滑动距离 disY = pageY - startPointY; if(Math.abs(disX)>Math.abs(disY)){//这里有个判断,如果水平滑动距离大于垂直滑动距离,就认为它是水平滑动,反之,是垂直滑动。 disX = disX+startEl;//用滑动距离加上起始位置距离就等于要设置的translate的距离 css(this,'translateX',disX);//设置移动的距离 css(this,'translateY',0);//水平滑动的时候设置垂直滑动距离为0,不会因为上一次垂直滑动的距离导致下一个li也滑动同样的距离 }else{ disY = disY+startElY; css(this,'translateY',disY);//设置移动的距离 } return false; }); oContent.addEventListener('touchend',function(e){ var oListTarget = maxTranslateX/size;//获取每个a平均滚动距离 targetY = css(this,'translateY');//获取当前垂直滑动位置 target = css(this,'translateX'); maxTranslateY = (document.documentElement.clientHeight-2.8*html)-this.offsetHeight;//不断更新最大垂直滑动距离 maxTranslateY = maxTranslateY >0?0:maxTranslateY;//如果li的高度小于可视区域的高度,就让它最大滑动距离为0,反之为maxtranslateY; index = Math.round(-target/aWidth);//更新li索引号 index = (index <=0?0:index>=size-1?size-1:index++);//如果当前li的索引号小于等于0,表示是第一个版面,让index为0,否则如果index>0t同时小于 最大索引号,让它索引号加1,以使得页面切换。 for(var i=0;i<oLi.length;i++){ oLi[i].className = ''; } oLi[index].className = 'current';//给a标签加选中样式 css(this,'translateX',-aWidth*index);//移动li到制定版面 this.style.height = oCon_child[index].offsetHeight+'px';//实时更新li的高度,为了获得每个li最大滑动距离 css(oList,'translateX',oListTarget*index);//滑动navInner if(targetY>minTranslateY){ targetY = 0; }else if(targetY < maxTranslateY){ targetY = maxTranslateY; } css(this,'translateY',targetY);//设置手指抬起,垂直滑动的距离 return false; }); };
通过对上面代码的分析,我对当初的思路是给肯定态度,但就是代码写的不美,朴实,就好比写文章,不精美,就是大白话,没关系,写代码的人都是不断努力进步的,未来两年我一定可以写出漂亮的代码,到时候不要把你看哭了。
关于整篇代码,你可以点击这里下载,测试哦。
转载:京东详情的一个滑屏切换