You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用hammer.js实现Tinder式滑动后,事件多次触发问题求助

解决Hammer.js实现Tinder卡片滑动时事件多次触发的问题

问题分析

你遇到的事件多次触发问题,主要源于以下几点:

  • 已标记为removed的卡片仍保留Hammer事件绑定,后续操作可能意外触发其panend回调
  • 缺少状态控制,同一卡片在滑动动画未完成时,可能被重复触发事件逻辑
  • 滑动完成后的业务函数没有防重复执行的限制

解决方案

1. 添加状态锁,避免同一卡片重复触发

在panend事件处理开头,检查卡片是否正在处理,若已在处理则直接返回,防止重复执行。

2. 销毁已移除卡片的Hammer实例

当卡片被标记为removed后,销毁对应的Hammer实例,彻底解绑事件,避免无效触发。

3. 优化事件绑定逻辑

确保每个卡片仅绑定一次Hammer事件,避免因重复初始化导致的多事件绑定。

修改后的代码

var allCards = document.querySelectorAll('.match--card');
var nope = document.getElementById('nope');
var love = document.getElementById('love');

allCards.forEach(function (el) {
  var hammertime = new Hammer(el);
  // 标记卡片是否正在处理滑动逻辑
  let isProcessing = false;

  hammertime.on('pan', function (event) {
    el.classList.add('moving');
  });

  hammertime.on('pan', function (event) {
    if (event.deltaX === 0) return;
    if (event.center.x === 0 && event.center.y === 0) return;

    matchContainer.classList.toggle('match_love', event.deltaX > 0);
    matchContainer.classList.toggle('match_nope', event.deltaX < 0);

    var xMulti = event.deltaX * 0.03;
    var yMulti = event.deltaY / 80;
    var rotate = xMulti * yMulti;

    event.target.style.transform = 'translate(' + event.deltaX + 'px, ' + event.deltaY + 'px) rotate(' + rotate + 'deg)';
  });

  hammertime.on('panend', function (event) {
    // 如果正在处理,直接返回
    if (isProcessing) return;
    isProcessing = true;

    var direction = event.direction;
    el.classList.remove('moving');
    matchContainer.classList.remove('match_love');
    matchContainer.classList.remove('match_nope');

    var moveOutWidth = document.body.clientWidth;
    var keep = Math.abs(event.deltaX) < 80 || Math.abs(event.velocityX) < 0.5;

    event.target.classList.toggle('removed', !keep);

    if (keep) {
      event.target.style.transform = '';
      // 处理完成,解锁
      isProcessing = false;
    } else {
      var endX = Math.max(Math.abs(event.velocityX) * moveOutWidth, moveOutWidth);
      var toX = event.deltaX > 0 ? endX : -endX;
      var endY = Math.abs(event.velocityY) * moveOutWidth;
      var toY = event.deltaY > 0 ? endY : -endY;
      var xMulti = event.deltaX * 0.03;
      var yMulti = event.deltaY / 80;
      var rotate = xMulti * yMulti;
      event.target.style.transform = 'translate(' + toX + 'px, ' + (toY + event.deltaY) + 'px) rotate(' + rotate + 'deg)';

      // 仅在有效滑动时执行业务函数
      if (direction === Hammer.DIRECTION_LEFT) {
        console.log('direction nope');
        bubble_fn_swipeNope()      
      } else if (direction === Hammer.DIRECTION_RIGHT) {
        console.log('direction love')
        bubble_fn_swipeLove()      
      }

      var activeCards = document.querySelectorAll('.match--card:not(.removed)').length;
      bubble_fn_activeCards(activeCards);

      // 销毁已移除卡片的Hammer实例,解绑事件
      hammertime.destroy();

      // 等待动画完成后再初始化新卡片,避免时序问题
      setTimeout(() => {
        initCards();
        // 处理完成,解锁
        isProcessing = false;
      }, 300);
    }
  });
});

function initCards(card, index) {
  var newCards = document.querySelectorAll('.match--card:not(.removed)');
  if (!newCards.length) {
    bubble_fn_activeCards(0);
  } else {
    var cL = newCards.length;
    bubble_fn_activeCards(cL);
    var card= newCards[0];
    var cardId = card.id;
    bubble_fn_activeCardUser(cardId);
  }

  newCards.forEach(function (card, index) {
    card.style.zIndex = allCards.length - index;
    card.style.transform = 'scale(' + (20 - index) / 20 + ') translateY(-' + 30 * index + 'px)';
    card.style.opacity = (10 - index) / 10;
  });

  matchContainer.classList.add('loaded');
}

initCards();

关键修改说明

  • 新增isProcessing状态锁,防止同一卡片在处理过程中被重复触发
  • 使用Hammer.DIRECTION_LEFT/Hammer.DIRECTION_RIGHT常量替代硬编码数字,提高可读性和稳定性
  • 卡片移除后调用hammertime.destroy()销毁实例,彻底解绑事件
  • 用setTimeout等待滑动动画完成后再初始化新卡片,避免时序问题导致的意外触发

内容的提问来源于stack exchange,提问作者mm1975

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:30:53