5

我将如何在 Hammer.js 中使用纯 JavaScript 进行 jQuery 样式的事件委托?例如:

Hammer(document).on('tap', '.item', function () {
  console.log('tapped')
})

这是直接可能的还是我必须自己做代表团?

4

4 回答 4

3

我使用以下函数来测试目标是否是委托。

function _getDelegate(selector, target, currentTarget) {

   var delegate = null;

   while (target && target != currentTarget) {
      delegate = $(target).filter(selector)[0];
      if (delegate) 
         return delegate;
      target = target.parentNode;
   }

   return delegate;

}

我正在使用 jquery 过滤器,因为我经常使用它并且使用了一些更复杂的选择器。

用法:

var delegationSelector = ".child";
$element.hammer()
$element.on("tap", function handler(event){
   var delegate = _getDelegate(delegationSelector, event.target, event.currentTarget);
   if(delegate){ // or if(!delegate) return;
      // Your handler code
   }
});

这不适用于所有选择器,但我会说它比 André 的更好,因为如果您的“目标”具有子元素,它仍然可以工作。例如

<div id="parent">
    <div class="child">
        <div class="text">Test</div>
    </div>
</div>

André's 在这里会失败,因为targetis[div.text]并且没有你的课程。

对于 _getDelegate 的上述用法,让我们说$element = $("#parent"). 如果您点击“测试”一词,event.target则将是[div.text](您点击的位置)并且event.currentTarget将是[div.parent](注册处理程序的位置)。当您_getDelegate使用这些参数调用时,您将收到[div.child]并知道您应该运行您的处理程序代码。

对于纯 JS 版本,您会想要这样的东西,您可以在其中循环遍历父母以查看您是否遇到任何问题。

var delegate;
var target = e.target; // e.g. Inner div
var currentTarget = e.currentTarget // e.g. #parent

while(target && target != currentTarget){
   if(target.className.indexOf('child')!=-1){
      delegate = target;
      break;
   }
   target = target.parentNode;
}

if( delegate ) {
   console.log('delegated tap received');
}

这方面还是有很多缺陷的。className 的整个 indexof 是一个坏主意,因为类可以是彼此的子字符串,例如“myClass”和“myClass2”。此外,我的代码假设您的所有子元素都位于它们的父元素中。

于 2014-08-22T15:17:00.750 回答
3

受 Jools 回答的启发,这就是我想出的。我并没有为纯 JS 解决方案而烦恼——事实上,这是为了与 a 一起使用Backbone.View,但很容易适应其他情况。

当它到达 View 的根元素 ( this.el) 时,它将停止爬升节点树。从 HammerJS 事件标识的目标开始,它将寻找与指定选择器匹配的第一个元素,undefined如果没有找到该元素则返回。

要在非主干环境中使用,只需传入对限制/包含元素的引用作为第三个参数(如在 Jools 的解决方案中)并使用它来替换this.el.

/**
 * @param {Node}target - the target of the received event
 * @param {String}selector - any jQuery-compatible selector
 */
getEventDelegate: function (target, selector) {
     var delegate;
     while (target && target != this.el) {
        delegate = $(target).filter(selector)[0];
        if (delegate) {
           return delegate;
        }
        target = target.parentNode;
     }
     return undefined;
  }

如果你有一个onTap回调函数,它可能看起来像这样:

/**
 * @param {Event}ev
 */
onTap: function (ev) {
   var target = this.getEventDelegate(ev.target, "#desiredTarget");
   if (target) {
      // TODO something with the target...
   }
}

为了把它全部连接起来,你会想要这样的东西......

this._hammer = new Hammer(this.el);
this._hammer.on('tap', _.bind(this.onTap, this));

(不要忘记this._hammer.destroy()在您的视图被破坏时调用!)

于 2015-04-07T17:36:14.463 回答
2

您只需要检查target传递给您的处理程序的 Event 对象。

这是一个演示

于 2013-07-26T11:47:29.403 回答
-1

继续@Lambarr 的解决方案 - 打字稿:

private delegateBind(rootElement:Node,e, selector:string, handler: (target:any) => any)
  {

    let target=e.target;
    let o = {

      getEventDelegate: function ()
      {
        var delegate;

        while (target && target != rootElement)
        {
          delegate = jQuery(target).filter(selector)[0];
          if (delegate)
          {
            return delegate;
          }

          target = target.parentNode;
        }
        return undefined;
      }

    };

     target = o.getEventDelegate();
    if (target)
    {
      handler(target);
    }
  }

用法 :

private registerDocumentclick()
  {

     Hammer(this.document).on('tap', e =>
        this.delegateBind(this.document,e,'.article', (elm) => console.log(elm.classList))

    );
  }
于 2017-04-16T18:55:03.537 回答