最近在做项目的时候遇到了个需求,在网页上实现类似于QQ会话列表那样子的左滑出现删除按钮的效果,于是尝试着写了一个,写出来与大家交流分享,大神勿喷。
基本要求
由于我们是在做一个跨平台的APP,里面部分界面其实就是WebView加载的网页,因此需要使用网页实现这样的效果:往左滑动时,显示删除按钮,再往右滑,隐藏删除按钮。
成品示例图
额,先上图吧。下面分别是在PC浏览器里和在Mobile浏览器里的效果。
PC浏览器
手机浏览器
实现思路
为了说明我的实现思路,做了两个图来辅助说明。
首先,请看图1。在图中,我们设置每一行的宽度超过浏览器的宽度,其超出的部分就是放置按钮的区域。由于超出了浏览器的最大宽度,因此按钮区域此时是不可见的,只能显示左侧的常规信息部分。
图1 普通状态
接下来,我们监听左侧常规信息区域,监听滑动事件(具体如何监听先不考虑)。当我们监听到左滑事件时,我们让相应行左偏移,让按钮显示出来,同时左侧超出的部分被遮挡(请看图2)。
图2 左滑状态
当我们右滑时,我们再让相应行回复到左偏移为0的时候就行了。
关键实现方式
对于左滑和右滑,我们通过设定常规信息区域的marin-left来实现,当设定margin-left为负值时,实现左滑,当再次设定margin-left为0时,实现右滑。
对于滑动事件监听,通过监听鼠标(手指)按下和抬起来实现,根据两点的X坐标的差值的正负判定是右滑还是左滑。
完整代码
需要注意的是,我在测试的时候用的是chrome的普通模式和mobile模拟器模式,发现两种模式下监听是不一样的,因此我写了两种监听,这样至少有一种会执行。也许有其他更好的适配方法,但不作为此处的重点。当然也欢迎大家赐教。
至于代码部分,用了jQuery,其实不用也没啥问题的,动画滑动和监听都可以用纯js写,但是由于这不是这里的重点,那么为什么不用jQuery呢?成功者站在巨人的肩膀上,而且咱也没有jQuery写的好 (。・`ω´・)
2015/11/13更新
有位同学提出说代码在QQ手机浏览器和Opera手机浏览器等中没有滑动效果,找了一下大概是帖子里说的原因,于是根据帖子里的提示以及那位同学的一个大神同学的提示,做了一下修改。主要是在touchmove事件中根据横纵坐标位移来判断是否阻止默认事件,如下:
// 横向位移大于纵向位移,阻止纵向滚动 if (Math.abs(delta.x) > Math.abs(delta.y)) { event.preventDefault(); }
2016/02/25更新
qq_25558115同学提到:“如果再能给大家提供出只能有一条记录可以左滑, 倘若滑动其他的记录,则有左滑记录的要回到原位”。于是进行了简单实现。主要思路如下:
// 用一个变量记录上一次左滑的对象 var lastLeftObj; // 在左滑发生的时候,判定上一个左滑的对象是否存在,若存在,且不是当前被左滑的对象,则将其右滑 // 同时,记录新的左滑对象 // 在右滑发生时,将上一个左滑对象清空 if (左滑) { pressedObj左滑 lastLeftObj && lastLeftObj != pressedObj && lastLeftObj右滑 lastLeftObj = pressedObj; // 记录上一个左滑的对象 } else if (右滑) { pressedObj右滑 lastLeftObj = null; // 清空上一个左滑的对象 }
2016/09/06更新
根据马灿发同学提出的bug进行修改:
右滑时进行判断,仅当要右滑的对象(pressedObj)是上一次左滑的对象(lastLeftObj)时才将对象右滑并清空lastLeftObj。
if (pressedObj == lastLeftObj) {...}
根据girlyougo同学的提议,添加“在除本行外的其他区域点击时均复位当前左滑按钮”的功能。思路为在滑动结束时,判定pressedObj!=lastLeftObj,即可知点击/滑动的对象为其他对象:
// 点击除当前左滑对象之外的任意其他位置 if (lastLeftObj && pressedObj != lastLeftObj) { $(lastLeftObj).animate({marginLeft:"0"}, 500); // 右滑 lastLeftObj = null; // 清空上一个左滑的对象 }
实际上,在添加了上述功能之后,前面提到的bug不存在了。不过此处保留了消除bug的那部分代码。
更新后的完整代码如下: