vue实现左滑删除功能

使用vue实现左滑删除的功能,效果图如下:

 

上代码:SlideToDel组件(子组件)代码:

<template>
  <div class="delete">
    <div class="slider">
      <div
        class="content"
        @touchstart="touchStart"
        @touchmove="touchMove"
        @touchend="touchEnd"
        :style="deleteSlider"
      >
        <!--  插槽中放具体项目中需要内容     -->
        <slot></slot>
      </div>
      <!--  左滑之后右侧显示的内容按钮     -->
      <div class="remove" ref="remove">
        <p v-for="item in handles" :key="item.id" @click="onClick(item.id)">{{item.title}}</p>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    // 当前组件的id
    sliderId: {
    },
    // 父组件当前移动的组件id
    curSlideID: {
    },
    sensitivity: { // 灵敏度(1 ~ 10)1 => 最细腻(跟手) 10 => 最灵敏
      type: Number,
      default: 5
    },
    handles: {
      type: Array,
      default: [{title: '删除', id: 0}]
    }
  },
  data() {
    return {
      startX: 0, //触摸开始位置
      endX: 0, //结束位置
      moveX: 0, //滑动时的位置
      disX: 0, //移动距离
      deleteSlider: "", //滑动时的效果
      wd: 0 // 左滑后显示出来的remove元素的宽度,设定为最大左滑距离
    };
  },
  mounted() {
    this.ready();
    // 左滑后显示出来的remove元素的宽度,设定为最大左滑距离
    this.wd = this.$refs.remove.offsetWidth
    if (this.handles.length > 3) {
      throw new Error('handles more than 3')
    }
    this.sensitivity = this.sensitivity > 10 ? 10 : (this.sensitivity < 1 ? 5 : this.sensitivity)
  },
  methods: {
    touchStart(ev) {
      ev = ev || event;
      //tounches类数组,等于1时表示此时有只有一只手指在触摸屏幕(在touchend时,此属性为空)
      if (ev.touches.length == 1) {
        // 记录开始位置
        this.startX = ev.touches[0].clientX;
      }
    },
    touchMove(ev) {
      ev = ev || event;
      if (ev.touches.length == 1) {
        // 滑动时距离浏览器左侧实时距离
        this.moveX = ev.touches[0].clientX;
        //起始位置减去 实时的滑动的距离,得到手指实时偏移距离
        this.disX = this.startX - this.moveX;
        // 如果是向右滑动或者不滑动,不改变滑块的位置
        if (this.disX < 0 || this.disX == 0) {
          this.deleteSlider = "transform:translateX(0px)";
          // 大于0,表示左滑了,此时滑块开始滑动
        } else if (this.disX > 0) {
          // 告知父组件当前向左滑动的组件id
          this.$emit("onSlide", this.sliderId);
          //具体滑动距离取的是 手指偏移距离 * sensitivity。
          this.deleteSlider = "transform:translateX(-" + this.disX * this.sensitivity + "px)";

          // 最大也只能等于删除按钮宽度
          if (this.disX * this.sensitivity >= this.wd) {
            this.deleteSlider = "transform:translateX(-" + this.wd + "px)";
          }
        }
      }
    },
    touchEnd(ev) {
      ev = ev || event;
      // touchEnd获取值为changedTouches,因为当touchend时,touches的值会被清空,详情可参考https://www.cnblogs.com/mengff/p/6005516.html
      if (ev.changedTouches.length == 1) {
        let endX = ev.changedTouches[0].clientX;
        this.disX = this.startX - endX;
        //如果距离小于删除按钮一半,强行回到起点
        if (this.disX * this.sensitivity < this.wd / 2) {
          this.deleteSlider = "transform:translateX(0px)";
        } else {
          //大于一半 滑动到最大值
          this.deleteSlider = "transform:translateX(-" + this.wd + "px)";
        }
      }
    },
    ready() {
      document.addEventListener("click", (e) => {
        // this.$el.contains(e.target) === 除了自己意外的其他元素,此处的作用是当用户点击其他组件,隐藏当前左滑的组件
        if (!this.$el.contains(e.target) && this.disX !== 0) {
          this.deleteSlider = "transform:translateX(-" + "0px)";
        }
      });
    },
    onClick(clickId) {
      // 将用户点击的操作id返回出去
      this.$emit("onClick", clickId);
    }
  },
  watch: {
    // 监听父组件的curSlideID值,和自己的sliderId比较,用以隐藏左滑的组件
    curSlideID(newVal, oldVal) {
      if (this.curSlideID !== this.sliderId && this.disX !== 0) {
        this.deleteSlider = "transform:translateX(-" + "0px)";
      }
    },
  },
};
</script>
<style>
.delete {
  height: 100%;
}
.slider {
  width: 100%;
  height: 100%;
  position: relative;
  user-select: none;
}
.content {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background: #ffffff;
  z-index: 100;
  transition: 0.3s;
}
.remove {
  position: absolute;
  min-width: 60px;
  max-width: 150px;
  height: 100%;
  background: red;
  right: 0;
  top: 0;
  color: #fff;
  text-align: center;
  font-size: 16px;
}
.remove p {
  min-width: 50px;
  max-width: 60px;
  height: 100%;
  float: left;
}
.remove > p:first-child {
  background: #5a6bfc
}
.remove > p:nth-child(2) {
  background: rgb(58, 235, 82);
}
.remove > p:last-child {
  background: none;
}
</style>

父组件代码:

<template>
  <div id="app">
    <div class="liDemo" v-for="item in list" :key="item.imgUrl">
      <SlideToDel
        @onClick="onClick"
        @onSlide="onSlide"
        :sliderId="item.id"
        :curSlideID="curSlideID"
        :handles="handles"
        :sensitivity="sensitivity"
      >
        <div class="df fg1 f-ac">
          <img :src="item.imgUrl" alt="" class="df f-js img" />
          <p class="df fg1">{{ item.title }}</p>
        </div>
      </SlideToDel>
    </div>
  </div>
</template>

<script>
import SlideToDel from "@/components/SlideToDel.vue";
export default {
  name: "App",
  components: {
    SlideToDel,
  },
  data: function () {
    return {
      list: [
        {
          imgUrl:
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608116221510&di=694852c91e552e68a670f82815d5ad97&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201305%2F30%2F220025pxfkhykvkgkvuktq.jpg",
          title: 0,
          id: 0,
        },
        {
          imgUrl:
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608122319754&di=baef1cc964e443464c02ea2ac9588b63&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201408%2F07%2F213601f2xz7usscm2z1mjh.jpg",
          title: 1,
          id: 1,
        },
        {
          imgUrl:
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608122326450&di=65f10f53b82d30037ce3c4bf17b4068c&imgtype=0&src=http%3A%2F%2Ff.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2F241f95cad1c8a7863cb5bacd6709c93d71cf5052.jpg",
          title: 2,
          id: 2,
        },
        {
          imgUrl:
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608122346127&di=b2e344cb29f3cd4b725b3b4bd18deb76&imgtype=0&src=http%3A%2F%2Fbenyouhuifile.it168.com%2Fforum%2F201304%2F06%2F11435052yrezzae1bua8ee.jpg",
          title: 3,
          id: 3,
        },
        {
          imgUrl:
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608122467284&di=3d3684c0fcd46a4936a375fb841929dc&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201403%2F01%2F134104shkenreehh21nol1.jpg",
          title: 4,
          id: 4,
        },
        {
          imgUrl:
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608122469971&di=c54f426772a69fa37150fce4cc1f5e68&imgtype=0&src=http%3A%2F%2Fattachments.gfan.com%2Fforum%2Fattachments2%2Fday_100430%2F10043015437962673bf6152eff.jpg",
          title: 5,
          id: 5,
        },
        {
          imgUrl:
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608122484081&di=215184f79d0ecc8597ea5c14f4bbb641&imgtype=0&src=http%3A%2F%2Fimg4.imgtn.bdimg.com%2Fit%2Fu%3D3579831024%2C633721272%26fm%3D214%26gp%3D0.jpg",
          title: 6,
          id: 6,
        }
      ],
      nihao: "bushiba",
      curSlideID: null,
      handles: [
        { title: "回复", id: 0 },
        // { title: "置顶", id: 1 },
        { title: "删除", id: 2 },
      ],
      sensitivity: 3
    };
  },
  methods: {
    onClick(val) {// 监听用户操作的,返回的val和handles对应
      console.log("csx click -> " + val);
    },
    onSlide(val) {// 监听当前滑动的哪个slider组件
      console.log("csx onSlide val:", val);
      this.curSlideID = val;
    },
  },
};
</script>

<style>
* {
  margin: 0;
  padding: 0;
}

html,
body,
#app {
  height: 100%;
}

#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  background: rgba(220, 220, 220);
}

ul,
li {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.liDemo {
  color: #000;
  margin-bottom: 3px;
  height: 60px;
  line-height: 60px;
}

.img {
  width: 20%;
  height: auto;
  margin: 5px;
}

.df {
  display: flex;
  display: -webkit-flex;
}
.fg1 {
  flex-grow: 1;
}
.f-ac {
  align-content: center;
  -webkit-align-content: center;
}
.f-js {
  justify-content: flex-start;
  -webkit-justify-content: flex-start;
}
.f-jc {
  justify-content: center;
  -webkit-justify-content: center;
}
</style>

优化:

1.独立出来当作组件,使用者可以自定义滑动的灵敏度,滑动出现的操作数目等等;

2.使用父子组件传值的方式实现隐藏当前滑块的功能,避免引入vuex,使其模块化更好

完整代码请见Vue-SlideToDel

==================================================================================================================================================

此贴为转载贴,感谢@a57521大牛的文章
文章链接:https://blog.csdn.net/weixin_42618523/article/details/102719197?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码主要是在Vue实现了购物车中的左滑删除效果。当点击红色区域时,会触发删除操作。具体的实现逻辑如下: - 在handleDelete方法中,首先会显示一个提示框,确认是否删除该商品。 - 如果确认删除,则会进行身份验证,确保用户已登录。 - 然后通过axios发送DELETE请求来删除该商品。 - 如果删除成功,则通过$emit方法触发getList事件,更新购物车列表。 - 如果删除失败,则会显示一个删除商品失败的提示。 此外,还引用了另外两个内容: - [2介绍了使用Vue实现移动端左滑删除效果的方法,对于实现左滑删除功能有一定的参考价值。 - [3介绍了滑动删除的原理,通过监听touch事件来判断左滑还是右滑,并根据滑动方向来显示或隐藏删除按钮。 所以,以上代码是实现Vue购物车左滑删除功能的一种方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [mpvue实现小程序购物车左滑删除功能](https://blog.csdn.net/qq_36070288/article/details/84881644)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [使用Vue实现移动端左滑删除效果附](https://download.csdn.net/download/weixin_38697979/12942257)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [vue实现购物车页面功能交互,单选、全选、左滑删除](https://blog.csdn.net/cd13849109771/article/details/120987420)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值