先看看效果是怎樣的!
我不會(huì)生成gif圖,在網(wǎng)上找了個(gè)在線生成的但是就是有個(gè)水印,有空了去學(xué)習(xí)一下怎么生成gif哈哈哈

先看看側(cè)邊欄都做了哪些事情,有什么效果?
- 可滑動(dòng)(touchmove)
- 點(diǎn)擊其中一個(gè)分類時(shí)會(huì)置頂
- 如果滑動(dòng)到無法滑動(dòng)的限值時(shí)再點(diǎn)擊其中分類不會(huì)置頂
簡(jiǎn)單分為這三個(gè)需求,然后分析一下如何實(shí)現(xiàn)
- 需要封裝一個(gè)點(diǎn)擊事件,因?yàn)閏lick會(huì)有約300ms的延遲
- 需要判斷是否已到達(dá)最大滑動(dòng)值,讓其點(diǎn)擊不再置頂
- 在還沒滑動(dòng)到最大滑動(dòng)值時(shí)點(diǎn)擊,需要移動(dòng)側(cè)邊欄,將當(dāng)前點(diǎn)擊的分類移動(dòng)到頂部
那么先看看結(jié)構(gòu)

看看結(jié)構(gòu)代碼
<div class="jd_layout">
<!--上圖中灰色框框:layout-->
<div class="jd_category">
<!--上圖中藍(lán)色框框:側(cè)邊欄盒子-->
<div class="jd_category_left">
<!--上圖中紅色框框:ul-->
<ul class="clearFix">
<li class="active"><a href="javascript:;">熱門推薦</a></li>
<li class=""><a href="javascript:;">潮流女裝</a></li>
<li class=""><a href="javascript:;">品牌男裝</a></li>
<li class=""><a href="javascript:;">內(nèi)衣配飾</a></li>
<li class=""><a href="javascript:;">家用電器</a></li>
<li class=""><a href="javascript:;">電腦辦公</a></li>
<li class=""><a href="javascript:;">手機(jī)數(shù)碼</a></li>
<li class=""><a href="javascript:;">母嬰頻道</a></li>
<li class=""><a href="javascript:;">圖書</a></li>
<li class=""><a href="javascript:;">家居家紡</a></li>
<li class=""><a href="javascript:;">居家生活</a></li>
<li class=""><a href="javascript:;">家具建材</a></li>
<li class=""><a href="javascript:;">熱門推薦</a></li>
<li class=""><a href="javascript:;">潮流女裝</a></li>
<li class=""><a href="javascript:;">品牌男裝</a></li>
<li class=""><a href="javascript:;">內(nèi)衣配飾</a></li>
<li class=""><a href="javascript:;">家用電器</a></li>
<li class=""><a href="javascript:;">電腦辦公</a></li>
<li class=""><a href="javascript:;">手機(jī)數(shù)碼</a></li>
<li class=""><a href="javascript:;">母嬰頻道</a></li>
<li class=""><a href="javascript:;">圖書</a></li>
<li class=""><a href="javascript:;">家居家紡</a></li>
<li class=""><a href="javascript:;">居家生活</a></li>
<li class=""><a href="javascript:;">家具建材</a></li>
</ul>
</div>
</div>
</div>
隨便寫了下樣式,有點(diǎn)丑,不要介意,這里就直接貼代碼了
<style type="text/css">
html,body{
height: 100%;
}
.jd_layout{
width: 100%;
height: 100%;
margin: 0 auto;
}
.jd_category{
width:100%;
position: absolute;
height: 100%;
/*padding-top: 45px;*/
}
.jd_category>.jd_category_left{
width: 100px;
height: 100%;
overflow: hidden;
float: left;
}
.jd_category>.jd_category_left>ul{
width: 100%;
}
.jd_category>.jd_category_left>ul>li{
width: 100%;
height: 50px;
border-right:1px solid #ccc;
border-bottom:1px solid #ccc;
background-color: #eee;
}
.jd_category>.jd_category_left>ul>li.active{
border:none;
background-color: #ffffff;
color: #e92322;
}
.jd_category>.jd_category_left>ul>li.active>a{
color: #e92322;
}
.jd_category>.jd_category_left>ul>li>a{
display: block;
width: 100%;
height: 50px;
text-align: center;
line-height:50px;
font-size:14px;
color: #000;
}
</style>
好了,現(xiàn)在才是重點(diǎn),開始一步一步實(shí)現(xiàn)效果
(1)獲取側(cè)邊欄盒子、側(cè)邊欄盒子高度、ul、ul高度
var parentBox=document.querySelector('.jd_category_left');
var ulBox=parentBox.querySelector('ul');
var ulHeight=ulBox.offsetHeight;
var parentHeight=parentBox.offsetHeight;
(2)定義最大和最小Y坐標(biāo),后面用于判斷滑動(dòng)限值。定義彈簧效果坐標(biāo)值
/*靜止?fàn)顟B(tài)下的最大Y坐標(biāo)值*/
var maxPosition=0;
/*靜止?fàn)顟B(tài)下最小的Y坐標(biāo)值*/
var minPosition=parentH-ulH;
/*彈簧效果最大的Y坐標(biāo)值*/
var bounceMaxPosition=maxPosition+100;
/*彈簧效果最小的Y坐標(biāo)值*/
var bounceMinPosition=minPosition-100;
(3)到這里,先添加幾個(gè)公共方法
1.添加過渡
2.刪除過渡
3.設(shè)置ul移動(dòng)
/*添加過渡*/
var openTransition=function(){
ulBox.style.transition="all .2s";
ulBox.style.webkitTransition="all .2s";
};
/*移除過渡*/
var removeTransition=function(){
ulBox.style.transition="none";
ulBox.style.webkitTransition="none";
};
/*設(shè)置偏移*/
var setTransform=function(distanceY){
ulBox.style.transform="translateY("+distanceY+"px)";
ulBox.style.webkitTransform="translateY("+distanceY+"px)";
}
(4)接下來,要添加touch事件了
記錄點(diǎn)擊的時(shí)候的坐標(biāo)
記錄滑動(dòng)的時(shí)候的坐標(biāo)
記錄距離
記錄上一次touch結(jié)束的位置,后面需要累計(jì)每次滑動(dòng)的距離
var startY=0;
var moveY=0;
var distanceY=0;
var currentY=0;
(5)給ul添加touchstart
ulBox.addEventListener("touchstart",function(e){
/*獲取起始位置*/
startY= e.touches[0].clientY;
});
(6)給ul添加touchmove
ulBox.addEventListener("touchmove",function(e){
/*獲取當(dāng)前手指滑動(dòng)的位置*/
moveY=e.touches[0].clientY;
/*計(jì)算本次的偏移值*/
distanceY=moveY-startY;
/*判斷當(dāng)前抖動(dòng)的距離,在之前的距離基礎(chǔ),是否已經(jīng)超出指定的范圍*/
if(currentY+distanceY > bounceMaxPosition){
console.log("別拉,沒啦");
currentY=bounceMaxPosition;
}
else if(currentY+distanceY < bounceMinPosition){
console.log("別拉,沒啦");
currentY=bounceMinPosition;
}
else{
/*移動(dòng)過渡*/
removeTransition();
/*設(shè)置偏移*/
setTransform(currentY+distanceY);
}
});
(7)給ul添加touchend
ulBox.addEventListener("touchend",function(e){
/*判斷當(dāng)前的位置是否在靜止?fàn)顟B(tài)最小Y坐標(biāo)之外--比它還小*/
if(currentY+distanceY < minPosition){
currentY=minPosition;
/*添加過渡*/
openTransition();
/*設(shè)置偏移*/
setTransform(currentY);
}
else if(currentY+distanceY > maxPosition){
currentY=maxPosition;
/*添加過渡*/
openTransition();
/*設(shè)置偏移*/
setTransform(currentY);
}
else{
/*松開手指,結(jié)束本次滑動(dòng)的時(shí)候,要將距離存儲(chǔ)到變量中*/
currentY+=distanceY;
}
});
(8)現(xiàn)在要給li標(biāo)簽設(shè)置索引了,因?yàn)橐c(diǎn)擊
/*設(shè)置li標(biāo)簽的自定義索引*/
var lis=ulBox.querySelectorAll("li");
for(var i=0;i<lis.length;i++){
/*lis[i].setAttribute("index",i);*/
/*賦值索引*/
lis[i].index=i;
}
(9)那么說到點(diǎn)擊,在移動(dòng)端click是由300ms延遲的,上面說到要封裝一個(gè)tap
var tap=function (dom,callback) {
/*1.不能滑動(dòng)過
* 2.end與start時(shí)間間隔一般在150ms內(nèi)*/
var isMove=false;//標(biāo)記是否滑動(dòng)過
var startTime=0;//記錄開始觸摸的時(shí)間
dom.addEventListener("touchstart",function(e){
/*記錄開始觸摸時(shí)間--以毫秒做為單位*/
startTime=Date.now();
});
dom.addEventListener("touchmove",function(e){
isMove=true;
});
dom.addEventListener("touchend",function(e){
if(isMove==false && Date.now()-startTime <=150){
callback && callback(e);
}
/*重置標(biāo)記是否滑動(dòng)*/
isMove=false;
});
}
(10)調(diào)用tap事件
/*傳入父容器,那么可以通過e.target屬性來獲取當(dāng)前真正進(jìn)行響應(yīng)的子元素--捕獲*/
tap(ulBox,function(e){
/*清除所有l(wèi)i標(biāo)簽的樣式*/
var activeLi=ulBox.querySelector(".active");
activeLi.classList.remove("active");
/*拿到所有l(wèi)i標(biāo)簽*/
var li= e.target.parentNode;
/*獲取li標(biāo)簽的高度*/
var liH=li.offsetHeight;
/*添加li標(biāo)簽的樣式*/
li.classList.add("active");
/*移動(dòng)需要先獲取當(dāng)前你所點(diǎn)擊的li標(biāo)簽的索引*/
var index=li.index;
/*判斷:如果在之前的移動(dòng)基礎(chǔ)之上(之前偏移的值在點(diǎn)擊過后,其實(shí)已經(jīng)包含在點(diǎn)擊的偏移值以內(nèi)) ,再進(jìn)行當(dāng)前點(diǎn)擊所需要的偏移,如果這個(gè)偏移值造成元素在靜止?fàn)顟B(tài)下Y坐標(biāo)的最小值以外,那么我們就應(yīng)該讓其Y固定在最小區(qū)間位置*/
if(-index*liH < minPosition){
currentY=minPosition;
openTransition();
setTransform(minPosition);
}
/*否則,就按正常方式進(jìn)行偏移,同時(shí)重置currentY的值,以便下次可以正常的滑動(dòng)*/
else{
/*開啟過渡*/
openTransition();
/*設(shè)置偏移*/
setTransform(-index*liH);
/*一定要記得一個(gè)事情,重置currentY*/
currentY=-index*liH;
}
})
總結(jié):
- 先讓ul能夠滑動(dòng)起來
- 然后記錄距離值(每次累計(jì))
- 在touch事件中判斷是否達(dá)到限值
- 給每個(gè)li賦值索引
- 點(diǎn)擊li后設(shè)置置頂(設(shè)置偏移,負(fù)的索引值*li的高度),同時(shí)判斷是否達(dá)到滑動(dòng)限制,如果達(dá)到則不能置頂