Vue 仿QQ左滑删除组件功能


Posted in Javascript onMarch 12, 2018

前几天在做Vue项目开发的时候,因为之前别人写的代码有点小 bug,有人反应 IOS 上面的滑动点击有点问题,于是让我来帮忙解决,我看了看以前的代码实现比较繁琐,冗余,索性就直接自己重新写了一套,供大家参考,如有更好的方式,欢迎及时交流~

我们先看看效果图吧,毕竟无图无真相啊~

效果图

Vue 仿QQ左滑删除组件功能 

实现思路

具体实现思路如下:

  • 布局方面我采用的是 rem + flex 布局,具体如何结构和样式可以参考我的代码,值得注意的是后面的删除按钮是我通过定位放在了每一行的最后,超出隐藏了而已
  • 左滑和右滑是通过 touchstart 和 touchend 事件,通过判断滑动开始和结束,水平方向 x 的偏移量,如果大于一定得阈值认为是左滑动,小于一定的阈值则认为是右滑动
  • 左滑动和右滑动分别都是通过父级 li 元素的 translate 偏移量进行变化的,这里我的实现方式是提前声明好样式,通过改变当前父级 li 的 type 值,进行样式切换
  • 点击某一个滑块的时候,首先判断当前所有的滑块是否有处于 滑出状态的 ,如果有,则必须先将所有的滑块状态还原,如果没有,则点击生效,我这里只是弹出一个 alter ,具体业务可以根据实际填写
  • 删除相对简单,当滑块画出后,出现删除按钮,点击按钮,拿到当前的数组索引值,通过数组的 splice 方法,删除对应的数组值即可

具体实现

Html代码

<div class="container">
  <div class="page-title">滑动组件</div>
  <ul>
    <li class="list-item " v-for="(item,index) in list " data-type="0">
      <div class="list-box" @touchstart.capture="touchStart" @touchend.capture="touchEnd" @click="skip">
        <img class="list-img" :src="item.imgUrl" alt="">
        <div class="list-content">
          <p class="title">{{item.title}}</p>
          <p class="tips">{{item.tips}}</p>
          <p class="time">{{item.time}}</p>
        </div>
      </div>
      <div class="delete" @click="deleteItem" :data-index="index">删除</div>
    </li>
  </ul>
</div>

注意:我这里的数据全是本地 mock 的~

Css样式代码

.page-title{
  text-align: center;
  font-size: 17px;
  padding: 10px 15px;
  position: relative;
}
.page-title:after{
  content: " ";
  position: absolute;
  left: 0;
  bottom: 0;
  right: 0;
  height: 1px;
  border-bottom: 1px solid #ccc;
  color: #ccc;
  -webkit-transform-origin: 0 100%;
  transform-origin: 0 100%;
  -webkit-transform: scaleY(0.5);
  transform: scaleY(0.5);
  z-index: 2;
}
.list-item{
  position: relative;
  height: 1.6rem;
  -webkit-transition: all 0.2s;
  transition: all 0.2s;
}
.list-item[data-type="0"]{
  transform: translate3d(0,0,0);
}
.list-item[data-type="1"]{
  transform: translate3d(-2rem,0,0);
}
.list-item:after{
  content: " ";
  position: absolute;
  left: 0.2rem;
  bottom: 0;
  right: 0;
  height: 1px;
  border-bottom: 1px solid #ccc;
  color: #ccc;
  -webkit-transform-origin: 0 100%;
  transform-origin: 0 100%;
  -webkit-transform: scaleY(0.5);
  transform: scaleY(0.5);
  z-index: 2;
}
.list-box{
  padding: 0.2rem;
  background: #fff;
  display: flex;
  align-items: center;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  justify-content: flex-end;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  font-size: 0;
}
.list-item .list-img{
  display: block;
  width: 1rem;
  height: 1rem;
}
.list-item .list-content{
  padding: 0.1rem 0 0.1rem 0.2rem;
  position: relative;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  overflow: hidden;
}
.list-item .title{
  display: block;
  color: #333;
  overflow: hidden;
  font-size: 15px;
  font-weight: bold;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.list-item .tips{
  display: block;
  overflow: hidden;
  font-size: 12px;
  color: #999;
  line-height: 20px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.list-item .time{
  display: block;
  font-size: 12px;
  position: absolute;
  right: 0;
  top: 0.1rem;
  color: #666;
}
.list-item .delete{
  width: 2rem;
  height: 1.6rem;
  background: #ff4949;
  font-size: 17px;
  color: #fff;
  text-align: center;
  line-height: 1.6rem;
  position: absolute;
  top:0;
  right: -2rem;
}

这是核心的样式代码,还有部分样式重置代码放在了 App.vue 里,通过计算根节点 html 的字体大小的脚本我放在了 index.html 中~

js代码

export default{
 name: 'index',
 data () {
 return {
  list : [
  {
   title : 'Chrome更新了' ,
   imgUrl : './static/images/Chrome.png' ,
   tips : '不再支持Flash视频播放' ,
   time : '上午 8:30'
  },
  {
   title : '电影新资讯' ,
   imgUrl : './static/images/Sina.png' ,
   tips : '电影《红海行动》上映以来票房暴涨,很多国人表示对国产电影有了新的改观' ,
   time : '上午 12:00'
  },
        {
   title : '聚焦两会·共筑中国梦' ,
   imgUrl : './static/images/video.png' ,
   tips : '习近平代表的两会故事' ,
   time : '下午 17:45'
        },
        {
   title : '微信团队' ,
   imgUrl : './static/images/Wechat.png' ,
   tips : '您的帐号有异常登录,如非本人操作,请及时修改密码' ,
   time : '昨天'
        }
  ],
  startX : 0 ,
  endX : 0 ,
 }
 },
 methods : {
 //跳转
 skip(){
  if( this.checkSlide() ){
  this.restSlide();
      }else{
  alert('You click the slide!')
      }
 },
 //滑动开始
 touchStart(e){
   // 记录初始位置
  this.startX = e.touches[0].clientX;
 },
 //滑动结束
 touchEnd(e){
            // 当前滑动的父级元素
  let parentElement = e.currentTarget.parentElement;
  // 记录结束位置
  this.endX = e.changedTouches[0].clientX;
            // 左滑
  if( parentElement.dataset.type == 0 && this.startX - this.endX > 30 ){
  this.restSlide();
  parentElement.dataset.type = 1;
  }
            // 右滑
  if( parentElement.dataset.type == 1 && this.startX - this.endX < -30 ){
  this.restSlide();
  parentElement.dataset.type = 0;
  }
  this.startX = 0;
  this.endX = 0;
 },
    //判断当前是否有滑块处于滑动状态
    checkSlide(){
  let listItems = document.querySelectorAll('.list-item');
  for( let i = 0 ; i < listItems.length ; i++){
  if( listItems[i].dataset.type == 1 ) {
   return true;
        }
  }
  return false;
    },
 //复位滑动状态
 restSlide(){
  let listItems = document.querySelectorAll('.list-item');
             // 复位
  for( let i = 0 ; i < listItems.length ; i++){
  listItems[i].dataset.type = 0;
  }
 },
 //删除
 deleteItem(e){
   // 当前索引
  let index = e.currentTarget.dataset.index;
  // 复位
  this.restSlide();
  // 删除
  this.list.splice(index,1);
 }
 }
}

js代码就这么一些,每个函数都有注释说明, 相信都能看得懂, 就不多解释了。

结语

怎么样,是不是也米有想象中的那么难,只要理清思路即可,实现起来也并不是那么困难,当然我这里写的只是我的一个实现思路而已,可能你们自己会有更好的实现方式,为什么不拿出来分享呢?

完整代码我已经托管到 gitlub 上了,欢迎下载使用并留言!

Javascript 相关文章推荐
Prototype使用指南之base.js
Jan 10 Javascript
asp 取文本框名称代码
Dec 02 Javascript
Lazy Load 延迟加载图片的 jQuery 插件
Feb 06 Javascript
ExtJS[Desktop]实现图标换行示例代码
Nov 17 Javascript
tangram框架响应式加载图片方法
Nov 21 Javascript
javascript框架设计之框架分类及主要功能
Jun 23 Javascript
你不需要jQuery(三) 新AJAX方法fetch()
Jun 14 Javascript
js中json处理总结之JSON.parse
Oct 14 Javascript
jQuery实现贪吃蛇小游戏(附源码下载)
Mar 04 Javascript
JS模拟实现哈希表及应用详解
May 04 Javascript
浅谈Vue render函数在ElementUi中的应用
Sep 06 Javascript
微信小程序tabBar 返回tabBar不刷新页面
Jul 25 Javascript
JS中touchstart事件与click事件冲突的解决方法
Mar 12 #Javascript
Node.JS循环删除非空文件夹及子目录下的所有文件
Mar 12 #Javascript
Javascript中prototype与__proto__的关系详解
Mar 11 #Javascript
js中document.write和document.writeln的区别
Mar 11 #Javascript
Javascript 编码约定(编码规范)
Mar 11 #Javascript
JavaScript获取移动设备型号的实现代码(JS获取手机型号和系统)
Mar 10 #Javascript
js经验分享 JavaScript反调试技巧
Mar 10 #Javascript
You might like
php设计模式 Decorator(装饰模式)
2011/06/26 PHP
ThinkPHP CURD方法之order方法详解
2014/06/18 PHP
WordPress特定文章对搜索引擎隐藏或只允许搜索引擎查看
2015/12/31 PHP
ThinkPHP简单使用memcache缓存的方法
2016/11/15 PHP
javascript 获取图片颜色
2009/04/05 Javascript
javascript获取当前日期时间及其它操作函数
2011/01/11 Javascript
尝试在让script的type属性等于text/html
2013/01/15 Javascript
JavaScript新窗口与子窗口传值详解
2014/02/11 Javascript
一个非常全面的javascript URL解析函数和分段URL解析方法
2014/04/12 Javascript
随机生成10个不重复的0-100的数字(实例讲解)
2017/08/16 Javascript
在页面中引入js的两种方法(推荐)
2017/08/29 Javascript
jQuery中extend函数简单用法示例
2017/10/11 jQuery
js 获取json数组里面数组的长度实例
2017/10/31 Javascript
代码详解JS操作剪贴板
2018/02/11 Javascript
Vue实现回到顶部和底部动画效果
2019/07/31 Javascript
Nodejs监听日志文件的变化的过程解析
2019/08/04 NodeJs
python中os操作文件及文件路径实例汇总
2015/01/15 Python
Python实现数据库编程方法详解
2015/06/09 Python
Python数据分析库pandas基本操作方法
2018/04/08 Python
python获取指定字符串中重复模式最高的字符串方法
2018/06/29 Python
python迭代dict的key和value的方法
2018/07/06 Python
使用python去除图片白色像素的实例
2019/12/12 Python
python爬虫今日热榜数据到txt文件的源码
2021/02/23 Python
Champion澳大利亚官网:美国冠军运动服装
2018/05/07 全球购物
药学专业个人自我评价
2013/11/11 职场文书
网上蛋糕店创业计划书
2014/01/24 职场文书
战友聚会主持词
2014/04/02 职场文书
启动仪式策划方案
2014/06/14 职场文书
自愿离婚协议书范本
2014/09/13 职场文书
六一儿童节标语
2014/10/08 职场文书
四风查摆问题及整改措施
2014/10/10 职场文书
2014小学教师个人工作总结
2014/11/10 职场文书
我的中国梦主题班会
2015/08/14 职场文书
优秀团员主要事迹材料
2015/11/05 职场文书
纯CSS实现酷炫的霓虹灯效果
2021/04/13 HTML / CSS
德劲DE1107指针试高灵敏度全波段收音机机评
2022/04/05 无线电