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 里待解决.