Demo gist地址 👈javascript
作web開發常常會遇到列表操做, 若是不涉及移動端, 那麼在列表上放幾個按鈕, 用戶點擊就完事了, 若是是移動端, 受限於屏幕寬度, 操做按鈕太多會影響佈局, 因此在移動端列表的滑動操做比較常見.html
作原生開發, 系統可能給列表提供了基本的刪除等功能, 那麼網頁應該如何實現呢?java
本文以地址管理爲demo, 用react實現, 其實無論是什麼框架, 涉及到的大部分都是 web 的接口.react
demo用到了coroutine, 使用協程方便管理一系列事件 (event flow).android
2件事要處理: 滑動 和 佈局ios
滑動事件須要被監聽, 應該在列表的每個item上設置監聽, 每一個item處理滑動事件.git
若是是 mobile 監聽這三個事件:github
不然監聽這幾個:web
在生命週期開始時候監聽這幾個事件:app
startupTouchEvent() {
const current = ReactDOM.findDOMNode(this);
current.addEventListener('touchstart', this.moveLoop);
current.addEventListener('touchend', this.moveLoop);
current.addEventListener('touchmove', this.moveLoop);
}
複製代碼
其中 this.moveLoop
是:
this.moveLoop = coroutine(function*() {
let e = {};
while (e = yield) {
if (e.type === 'touchstart') {
// trace position
const startX = e.touches[0].clientX;
while (e = yield) {
if (e.type === 'touchmove') {
// trace position
// console.log('touchmove', e);
const movedX = e.changedTouches[0].clientX;
const deltaX = movedX - startX;
// console.log('moved', deltaX);
if (deltaX <= 0) {
that.moveMask(deltaX);
}
}
if (e.type === 'touchend') {
const endX = e.changedTouches[0].clientX;
const deltaX = endX - startX;
// console.log('end', deltaX);
if (deltaX >= -40) {
that.closeMaskIfNeeded();
} else {
that.openMask();
}
break;
}
}
}
}
})
複製代碼
這裏用到了 corutine.
首先當手指放到 item 上時, 記錄位置 startX = e.touches[0].clientX;
.
當手指滑動時獲取此時的位置 e.changedTouches[0].clientX
, 減去初始位置 deltaX = movedX - startX;
, 若是 deltaX
小於0, 那麼此時是左滑, 進行 UI 上的操做, 將上層 div
左移 deltaX
.
當手指離開屏幕時候, 記錄此時位置並獲取與初始位置的差值 deltaX = endX - startX
, 判斷 deltaX
, 若是滑動距離過小(40px)或者向右滑, 那麼就關掉展開的 div
, 若是滑動距離夠長, 那麼就徹底展開 div
.
<div className="address-swipe-wrapper">
<div className="swiper-operation-btns">
<button style={{ backgroundColor: '#7EA1D6' }} onClick={onEdit}>
編輯
</button>
<button style={{ backgroundColor: 'red' }} onClick={onDelete}>
刪除
</button>
</div>
<div className="address-item" onClick={onClick} style={{ left, position: 'relative', transition: 'all 250ms', }}>
{selected &&
<img className="address-item-selected-icon" src={require('../img/check.png')} alt="選中" />
}
<div className="address-content">
<div>{`${name} ${mobile}`}</div>
<div>{provinceName+cityName+districtName+detailedAddress}</div>
</div>
</div>
</div>
複製代碼
幾個操做按鈕是絕對佈局被蓋在 address-item 內容的下面, 當滑動或者展開時候 address-item 會左移 left
距離, 它是 relative 佈局.
爲了讓滑動有動效, 能夠添加 transition: 'all 250ms'
.
openMask() {
this.setState({
left: -160
});
}
moveMask(deltaX) {
this.setState({
left: deltaX
});
}
closeMaskIfNeeded() {
this.setState({
left: 0
});
}
複製代碼
不會, 通過pc和手機(ios/android)嘗試, 滑動時候不會觸發 address-item 的選中, 並沒發現會衝突, 除非你寫 evt.preventDefault()
.
給 window
添加監聽事件:
window.addEventListener('touchstart', this.closeMaskIfNeeded);
複製代碼
在 PC 上表現良好, 可是在 mobile 上表現異常. 因此移到 TODO 裏待解決.