寫在前面
接着之前的移動端效果講解,剛好項目中需要使用到這一效果,去餓了么的組件庫看了一下效果,發現效果和微信端的cellSwiper
還是有點差別的,由於項目中又是使用的React
,之前使用的React
所有組件都是自己一個字母一個字母碼起來的(想來也是辛酸),所以結合之前的swiper
,道理類似,實現了類似微信端的抽拉效果。
代碼看這里:github
1. 核心解析
1.1 HTML結構
<div class="c-cell-swiper" id="wrapper">
<div class="cell-content" id="content">
<div class="your-code">
<img class="icon" src="./images/t.jpg"></img>
<div class="left">
<span>萌萌的卡洛奇</span>
<p class="sub">我這個月要來看你啦</p>
</div>
<div class="right">now</div>
</div>
</div>
<div class="cell-btn-group" id="btnGroup">
<div class="cell-btn">標為未讀</div>
<div class="cell-btn">刪除</div>
</div>
</div>
代碼中類名為your-code
的地方是你自己要加的代碼。
做一個效果之前,我們先需要分析一下我們應該怎么做,這樣才能有的放矢。比如這個效果,由於采用的是覆蓋式抽拉,因此,需要兩個層,上面一個層負責滑動,下面一個層固定,當上面的層滑動完成之后,下面的自然就顯示出來了。
因此有兩個點:
- 上層和下層的層都要絕對定位,這樣才好區別層級(最開始我試的是上面的層不需要決定定位,發現移到項目中的時候,下面的層顯示不出來,因為最開始設置了
z-index:-1
。但一般的頁面來說,body
其實是有一個層級的,因此就會覆蓋下面的層,導致顯示不出來) - 既然都采用絕對定位,那么上面的層級的高度就需要計算
1.2 代碼分析
定位好層級之后,下面的按鈕層就可以基本不用管了,主要的操作還是滑動。滑動可以借鑒之前的swiper代碼,這里不作贅述。
1.2.1 計算高度和按鈕組的寬度
var el = document.querySelector('#content');
var btn = document.querySelector('#btnGroup');
var wrapper = document.querySelector('#wrapper');
function getBtnGroupWidth() {
// 按鈕組的寬度,滑動的最大距離
btnGroupWidth = btn.getBoundingClientRect().width;
wrapperHeight = el.getBoundingClientRect().height;
// 設置最上層容器的高度
wrapper.style.height = wrapperHeight + 'px';
// 設置子容器高度
el.children[0].style.height = wrapperHeight + 'px';
// 設置按鈕組的line-height,保證按鈕組文字居中
btn.style.lineHeight = wrapperHeight + 'px';
}
1.2.2 滑動
// 滑動中 ontouchmove
// ...
// 這里計算的是上層滑動的距離范圍
// 滑動最遠不能超過按鈕組寬度
// 滑動最小距離就是不滑動,也就是0
offsetLeft = Math.min(Math.max(-btnGroupWidth, offsetLeft), 0);
translate(el, offsetLeft);
// ...
// 滑動結束 ontouchend
// ...
// 如果是tap, 直接關閉
if (dragDuration < 300) {
var fireTap = Math.abs(offsetLeft) < 5 && Math.abs(offsetTop < 5);
if (isNaN(offsetLeft) || isNaN(offsetTop)) {
fireTap = true;
}
if (fireTap) {
translate(el, 0, 150);
opened = false;
swiping = false;
return;
}
}
var distanceX = Math.abs(offsetLeft);
// 如果向左滑動超過了按鈕組的40%,辣么在松手的一刻自動滑開
// 反之如果向右滑動超過了按鈕組的40%就關閉
if (distanceX > btnGroupWidth * 0.4 && offsetLeft < 0) {
translate(el, -btnGroupWidth, 150);
opened = true;
} else {
translate(el, 0, 150);
opened = false;
}
// ...
2. 總結
整個流程來說相當於swiper
還是相當簡單的,可以說其實就是一個swiper
的簡化版本。
重點在於拿到一個效果之后如何分析,只有有清晰的分析思路才能針對這個分析來給出合理的解決方案。這里僅僅記錄自己做這個效果的歷程,拿出來共享,希望對大家有所幫助。