左滑删除

成品示例图

额,先上图吧。下面分别是在PC浏览器里和在Mobile浏览器里的效果。

PC浏览器

手机浏览器

实现思路

为了说明我的实现思路,做了两个图来辅助说明。

  1. 首先,请看图1。在图中,我们设置每一行的宽度超过浏览器的宽度,其超出的部分就是放置按钮的区域。由于超出了浏览器的最大宽度,因此按钮区域此时是不可见的,只能显示左侧的常规信息部分。

    图1 普通状态 

  2. 接下来,我们监听左侧常规信息区域,监听滑动事件(具体如何监听先不考虑)。当我们监听到左滑事件时,我们让相应行左偏移,让按钮显示出来,同时左侧超出的部分被遮挡(请看图2)。

    图2 左滑状态 

  3. 当我们右滑时,我们再让相应行回复到左偏移为0的时候就行了。

关键实现方式

  • 对于左滑和右滑,我们通过设定常规信息区域的marin-left来实现,当设定margin-left为负值时,实现左滑,当再次设定margin-left为0时,实现右滑。
  • 对于滑动事件监听,通过监听鼠标(手指)按下和抬起来实现,根据两点的X坐标的差值的正负判定是右滑还是左滑。

完整代码

需要注意的是,我在测试的时候用的是chrome的普通模式和mobile模拟器模式,发现两种模式下监听是不一样的,因此我写了两种监听,这样至少有一种会执行。也许有其他更好的适配方法,但不作为此处的重点。当然也欢迎大家赐教。

至于代码部分,用了jQuery,其实不用也没啥问题的,动画滑动和监听都可以用纯js写,但是由于这不是这里的重点,那么为什么不用jQuery呢?成功者站在巨人的肩膀上,而且咱也没有jQuery写的好 (。?`ω′?)

2015/11/13更新

有位同学提出说代码在QQ手机浏览器和Opera手机浏览器等中没有滑动效果,找了一下大概是这个帖子http://bbs.mb.qq.com/thread-201794-1-1.html里说的原因,于是根据帖子里的提示以及那位同学的一个大神同学的提示,做了一下修改。主要是在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的那部分代码。

更新后的完整代码如下:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>左划出现删除按钮,右滑隐藏</title>
<script type="text/javascript" src="jquery-1.11.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function(e) {
    // 设定每一行的宽度=屏幕宽度+按钮宽度
    $(".line-scroll-wrapper").width($(".line-wrapper").width() + $(".line-btn-delete").width());
    // 设定常规信息区域宽度=屏幕宽度
    $(".line-normal-wrapper").width($(".line-wrapper").width());
    // 设定文字部分宽度(为了实现文字过长时在末尾显示...)
    $(".line-normal-msg").width($(".line-normal-wrapper").width() - 280);

    // 获取所有行,对每一行设置监听
    var lines = $(".line-normal-wrapper");
    var len = lines.length;
    var lastX, lastXForMobile;

    // 用于记录被按下的对象
    var pressedObj;  // 当前左滑的对象
    var lastLeftObj; // 上一个左滑的对象

    // 用于记录按下的点
    var start;

    // 网页在移动端运行时的监听
    for (var i = 0; i < len; ++i) {
        lines[i].addEventListener(‘touchstart‘, function(e){
            lastXForMobile = e.changedTouches[0].pageX;
            pressedObj = this; // 记录被按下的对象 

            // 记录开始按下时的点
            var touches = event.touches[0];
            start = {
                x: touches.pageX, // 横坐标
                y: touches.pageY  // 纵坐标
            };
        });

        lines[i].addEventListener(‘touchmove‘,function(e){
            // 计算划动过程中x和y的变化量
            var touches = event.touches[0];
            delta = {
                x: touches.pageX - start.x,
                y: touches.pageY - start.y
            };

            // 横向位移大于纵向位移,阻止纵向滚动
            if (Math.abs(delta.x) > Math.abs(delta.y)) {
                event.preventDefault();
            }
        });

        lines[i].addEventListener(‘touchend‘, function(e){
            if (lastLeftObj && pressedObj != lastLeftObj) { // 点击除当前左滑对象之外的任意其他位置
                $(lastLeftObj).animate({marginLeft:"0"}, 500); // 右滑
                lastLeftObj = null; // 清空上一个左滑的对象
            }
            var diffX = e.changedTouches[0].pageX - lastXForMobile;
            if (diffX < -150) {
                $(pressedObj).animate({marginLeft:"-132px"}, 500); // 左滑
                lastLeftObj && lastLeftObj != pressedObj &&
                    $(lastLeftObj).animate({marginLeft:"0"}, 500); // 已经左滑状态的按钮右滑
                lastLeftObj = pressedObj; // 记录上一个左滑的对象
            } else if (diffX > 150) {
              if (pressedObj == lastLeftObj) {
                $(pressedObj).animate({marginLeft:"0"}, 500); // 右滑
                lastLeftObj = null; // 清空上一个左滑的对象
              }
            }
        });
    }

    // 网页在PC浏览器中运行时的监听
    for (var i = 0; i < len; ++i) {
        $(lines[i]).bind(‘mousedown‘, function(e){
            lastX = e.clientX;
            pressedObj = this; // 记录被按下的对象
        });

        $(lines[i]).bind(‘mouseup‘, function(e){
            if (lastLeftObj && pressedObj != lastLeftObj) { // 点击除当前左滑对象之外的任意其他位置
                $(lastLeftObj).animate({marginLeft:"0"}, 500); // 右滑
                lastLeftObj = null; // 清空上一个左滑的对象
            }
            var diffX = e.clientX - lastX;
            if (diffX < -150) {
                $(pressedObj).animate({marginLeft:"-132px"}, 500); // 左滑
                lastLeftObj && lastLeftObj != pressedObj &&
                    $(lastLeftObj).animate({marginLeft:"0"}, 500); // 已经左滑状态的按钮右滑
                lastLeftObj = pressedObj; // 记录上一个左滑的对象
            } else if (diffX > 150) {
              if (pressedObj == lastLeftObj) {
                $(pressedObj).animate({marginLeft:"0"}, 500); // 右滑
                lastLeftObj = null; // 清空上一个左滑的对象
              }
            }
        });
    }
});
</script>
<style type="text/css">
* { margin: 0; padding: 0; }
.line-wrapper { width: 100%; height: 144px; overflow: hidden; font-size: 28px; border-bottom: 1px solid #aaa; }
.line-scroll-wrapper { white-space: nowrap; height: 144px; clear: both; }
.line-btn-delete { float: left; width: 132px; height: 144px; }
.line-btn-delete button { width: 100%; height: 100%; background: red; border: none; font-size: 24px; font-family: ‘Microsoft Yahei‘; color: #fff; }
.line-normal-wrapper { display: inline-block; line-height: 100px; float: left; padding-top: 10px; padding-bottom: 10px; }
.line-normal-icon-wrapper { float: right; width: 120px; height: 120px; margin-right: 12px; }
.line-normal-icon-wrapper img { width: 120px; height: 120px; }
.line-normal-avatar-wrapper { width: 100px; height: 124px; float: left; margin-left: 12px; }
.line-normal-avatar-wrapper img { width: 92px; height: 92px; border-radius: 60px; }
.line-normal-left-wrapper { float: left; overflow: hidden; }
.line-normal-info-wrapper { float: left; margin-left: 10px; }
.line-normal-user-name { height: 28px; line-height: 28px; color: #4e4e4e; margin-top: 7px; }
.line-normal-msg { height: 28px; line-height: 28px; overflow:hidden; text-overflow:ellipsis; color: #4e4e4e; margin-top: 11px; }
.line-normal-time { height: 28px; line-height: 28px; color: #999; margin-top: 11px; }
</style>
</head>
<body>
<div class="line-wrapper">
  <div class="line-scroll-wrapper">
    <div class="line-normal-wrapper">
      <div class="line-normal-left-wrapper">
        <div class="line-normal-avatar-wrapper"><img src="1.jpg" /></div>
        <div class="line-normal-info-wrapper">
          <div class="line-normal-user-name">蜡笔小新</div>
          <div class="line-normal-msg">在同行的小伙伴中提到了你</div>
          <div class="line-normal-time">1分钟前</div>
        </div>
      </div>
      <div class="line-normal-icon-wrapper"><img src="5.jpg"/></div>
    </div>
    <div class="line-btn-delete"><button>删除</button></div>
  </div>
</div>
<div class="line-wrapper">
  <div class="line-scroll-wrapper">
    <div class="line-normal-wrapper">
      <div class="line-normal-left-wrapper">
        <div class="line-normal-avatar-wrapper"><img src="2.jpg" /></div>
        <div class="line-normal-info-wrapper">
          <div class="line-normal-user-name">乔巴</div>
          <div class="line-normal-msg">你看不到我哦</div>
          <div class="line-normal-time">1分钟前</div>
        </div>
      </div>
      <div class="line-normal-icon-wrapper"><img src="6.jpg"/></div>
    </div>
    <div class="line-btn-delete"><button>删除</button></div>
  </div>
</div>
<div class="line-wrapper">
  <div class="line-scroll-wrapper">
    <div class="line-normal-wrapper">
      <div class="line-normal-left-wrapper">
        <div class="line-normal-avatar-wrapper"><img src="3.jpg" /></div>
        <div class="line-normal-info-wrapper">
          <div class="line-normal-user-name">贱行贱远</div>
          <div class="line-normal-msg">回忆里想起模糊的小时候,云朵漂浮在蓝蓝的天空,那时的你说,要和我手牵手,一起走到时间的尽头</div>
          <div class="line-normal-time">1分钟前</div>
        </div>
      </div>
      <div class="line-normal-icon-wrapper"><img src="7.jpg"/></div>
    </div>
    <div class="line-btn-delete"><button>删除</button></div>
  </div>
</div>
<div class="line-wrapper">
  <div class="line-scroll-wrapper">
    <div class="line-normal-wrapper">
      <div class="line-normal-left-wrapper">
        <div class="line-normal-avatar-wrapper"><img src="4.png" /></div>
        <div class="line-normal-info-wrapper">
          <div class="line-normal-user-name">小黄人</div>
          <div class="line-normal-msg">哈哈哈哈哈……暑假来看小黄人电影哦~哈哈哈……</div>
          <div class="line-normal-time">1分钟前</div>
        </div>
      </div>
      <div class="line-normal-icon-wrapper"><img src="8.jpg"/></div>
    </div>
    <div class="line-btn-delete"><button>删除</button></div>
  </div>
</div>
</body>
</html>

总结

代码还比较粗糙,存在很多bug,也有些地方不是那么绝对。比如当我按下时是在第一条记录,然后抬起时是在第二条记录,那么这时候滑动将是第一条记录。但是这个看具体需求了,如果你觉得滑动的对象应该以按下去时的对象为准的话,那就不管在哪抬起都滑动那个按下时的对象;如果你觉得滑动的对象应该是抬起时的对象,那也没问题,或者你觉得按下和抬起时不是同一个对象就不滑动任何对象那也行。总之,看需求。

大家可以下载源码试一试哈~

源码请戳:源码下载

时间: 2024-10-05 03:27:39

左滑删除的相关文章

qq联系人 左滑删除功能

// 局部刷新 NSArray *indexPaths = @[ [NSIndexPath indexPathForRow:0 inSection:0], [NSIndexPath indexPathForRow:1 inSection:0] ]; [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft]; #pragma mark - 按钮的点击 - (IBAc

ANDROID仿IOS微信滑动删除_SWIPELISTVIEW左滑删除例子

http://dwtedx.sinaapp.com/itshare_290.html 本例子实现了滑动删除ListView的Itemdemo的效果.大家都知道.这种创意是来源于IOS的.左滑删除的功能.在Android上面实现比较麻烦.本例子中不仅实现了左滑删除功能.还实现了左滑赞.左滑分享.左滑收藏等功能.当然大家也可以根据自己项目的需求来修改功能.QQ和微信也实现了相同的功能.大家可以看看.先上程序运行的效果 怎么样.大家看了这个截图是不是很心动呀.而且在左滑的时候还配有简单的滑动动画呢.非

JS模拟左滑删除

接触前端有半年的时间了,不会的都会去搜索别人的代码,这是本人第一篇博客,也是因为在搜索了很多关于左滑删除的例子,但是结果并不是很好,虽然样式上面实现了,但是大多数都会有无法点击删除或是无法控制事件的困扰,所以简单整理一种写法,菜鸟一只,只求不喷~ 先简单说一下思路,在一个container容器里面,定义两个平级的标签   [显示内容+删除按钮],,按钮绝对定位在右侧,z-index 在后方,需要固定宽度,当滑动显示内容的部分,按钮显示出来.通过 active 的添加和删除实现,下面是代码部分:

Android开发学习之路-PopupWindow和仿QQ左滑删除

这周作业,要做一个类似QQ的左滑删除效果的ListView,因为不想给每个item都放一个按钮,所以决定用PopupWindow,这里记录一下 先放一下效果图: 先说明一下这里面的问题: ①没有做到像QQ那样可以允许item跟随手指移动,虽然PopupWindow有update方法让我们动态移动,但是在屏幕外移动会没有动画效果,直接弹进来 ②仔细观察可以发现,item的滑动和删除按钮的滑动是分开的,无法保证它们会一起播放,QQ的动画可以 再说说大概的思路,因为我们没有让item都带上Button

ListView左滑删除&amp;代理模式

要实现类似QQ的ListView左滑删除其实可以给ListView中每个条目外面添加一个可以处理左滑事件的View即可.该控件需要重写onInterceptTouchEvent方法和onTouchEvent方法,具体处理过程参考 安卓事件分发机制,确定由自定义控件处理触摸事件后需要调用requestDisallowInterceptTouchEvent来防止ListView响应事件. 下面介绍如何通过代理来实现. public class SlideListView extends ListVi

微信小程序实现左滑删除源码

左滑删除效果在app的交互方式中十分流行,比如全民应用微信 微信左滑删除 再比如曾引起很大反响的效率app Clear Clear左滑删除 从技术上来说,实现这个效果并不困难,响应一下滑动操作,移动一下组件,再加上些坐标计算,状态记录就可以了.也有一些文章介绍了在小程序上如何实现这一效果,不过我基本可以确定这些开发者没有在真机上详细测试,因为经我实践发现,在小程序上想要完美实现这个效果几乎是不可能完成的任务. 这一切要从小程序的事件机制说起.对于滑动类操作,小程序提供了bind和catch两种响

类似QQ消息左滑删除的Demo

最近在网上学到一篇类似QQ消息左滑删除的demo,完善了下代码,感觉还不错,特此分享一波: CustomSwipeListView.java 是个继承自ListView的类,里面调用了自定义View 类SwipeItemView.java的一个收缩的方法.其实QQ消息删除这个动画可以有很多种方法实现,这里我们介绍的方法是:常规ListView的每个Item展示方式不变,只是在Adapter类里面去绑定该显示的数据和删除等字样.具体详见如下: 自定义的ListView: package com.r

模仿QQ左滑删除

需求: 1.左滑删除 2.向左滑动距离超过一半的时候让它自动滑开,向右滑动超过一半的时候自动隐藏 3.一次只允许滑开一个item 还有,根本不需要自定义view来实现,谨防入坑 布局: <?xml version="1.0" encoding="utf-8"?> <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android" and

Android自定义组合控件---教你如何自定义下拉刷新和左滑删除

绪论 最近项目里面用到了下拉刷新和左滑删除,网上找了找并没有可以用的,有比较好的左滑删除,但是并没有和下拉刷新上拉加载结合到一起,要不就是一些比较水的结合,并不能在项目里面使用,小编一着急自己组合了一个,做完了和QQ的对比了一下,并没有太大区别,今天分享给大家,其实并不难,但是不知道为什么网上没有比较好的Demo,当你的项目真的很急的时候,又没有比较好的Demo,那么"那条友谊的小船儿真是说翻就翻啊",好了,下面先来具体看一下实现后的效果吧: 代码已经上传到Github上了,小伙伴们记

黑暗料理一之修改UITableViewCell左滑删除按钮的样式和自定义

在日常开发中我们可能会遇到需要自定义UITableViewCell左滑删除按钮的样式,网上也有许多自定义的第三方,但是都太重量级了,应为我们可能我们的需求很小,也不想大动干戈的导入一个第三方,然后设置各种一大堆属性,太麻烦了,那么怎么来修改系统自带的呢? 可能你说不能修改,万是不是绝对的,我们有神器reveal,作为一名iOS程序猿,如果你连reveal都不知道或不会用的话你就太low了,OK,我们开始我们的黑暗料理. 首先我们来看reveal下UITableViewCell左滑按钮的层级关系,