欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于jQuery的左滑出现删除按钮的示例

程序员文章站 2022-11-26 12:34:32
最近在做项目的时候遇到了个需求,在网页上实现类似于qq会话列表那样子的左滑出现删除按钮的效果,于是尝试着写了一个,写出来与大家交流分享,大神勿喷。 基本要求 由于我们是...

最近在做项目的时候遇到了个需求,在网页上实现类似于qq会话列表那样子的左滑出现删除按钮的效果,于是尝试着写了一个,写出来与大家交流分享,大神勿喷。

基本要求

由于我们是在做一个跨平台的app,里面部分界面其实就是webview加载的网页,因此需要使用网页实现这样的效果:往左滑动时,显示删除按钮,再往右滑,隐藏删除按钮。

成品示例图

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

pc浏览器

基于jQuery的左滑出现删除按钮的示例

手机浏览器

基于jQuery的左滑出现删除按钮的示例

实现思路

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

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

基于jQuery的左滑出现删除按钮的示例

图1 普通状态

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

基于jQuery的左滑出现删除按钮的示例

图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的那部分代码。

更新后的完整代码如下:

<!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,也有些地方不是那么绝对。比如当我按下时是在第一条记录,然后抬起时是在第二条记录,那么这时候滑动将是第一条记录。但是这个看具体需求了,如果你觉得滑动的对象应该以按下去时的对象为准的话,那就不管在哪抬起都滑动那个按下时的对象;如果你觉得滑动的对象应该是抬起时的对象,那也没问题,或者你觉得按下和抬起时不是同一个对象就不滑动任何对象那也行。总之,看需求。

源码请戳:源码下载

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。