我该如何使用纯JavaScript在Hammer.js中实现类似于jQuery风格的事件委托?例如:
这是直接可能的,还是我需要自己委托?
Hammer(document).on('tap', '.item', function () {
console.log('tapped')
})
这是直接可能的,还是我需要自己委托?
Hammer(document).on('tap', '.item', function () {
console.log('tapped')
})
受Jools答案的启发,以下是我的解决方案。我没有费心提供纯JS的解决方案——实际上,这是用于Backbone.View
的,但可以轻松适应其他情况。
当它到达View的根元素(this.el
)时,它将停止爬升节点树。从由HammerJS事件标识的目标开始,它将寻找与指定选择器匹配的第一个元素,并且如果找不到这样的元素,则返回undefined
。
要在非Backbone环境中使用,只需将限制/包含元素的引用作为第三个参数传入(如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()
!)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;
}
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>
由于target
是[div.text]
并且没有您的类,因此André在这里会失败。
对于上述使用_getDelegate的情况,假设$element = $("#parent")
。如果您点击了单词“Test”,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"。另外,我的代码假设所有子元素都在其父元素内定位。
_isDelegate
方法提供一个使用示例和/或参数文档会更有帮助。另外,_getDelegate
作为名称是否更准确,因为它不返回布尔值? :) - Lambarttarget
即可。
Hammer(document).on('tap', '.item', function () { console.log('tapped') })
- 而目标不是帮手 :-) - Royi Namir.item
的按钮 http://jsbin.com/hobenunale/1/edit?html,js,output - 而jQuery会向您显示委托的元素。 - Royi Namir继续@Lambarr的解决方案 - TypeScript:
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))
);
}
.item
的元素时才有效。但是,如果在该.item
中存在另一个元素并且您单击该内部元素,则检查目标将无法帮助您。您需要扫描其父级(这就是其他答案提供的内容)- 这正是您在问题中想要的$.on('tap', '.item', function () {...}
。使用jquery - 使用您在问题中的代码,即使您单击了.item
的内部元素,也会提供正确的信息。 - Royi Namir.item
的按钮 http://jsbin.com/hobenunale/1/edit?html,js,output - 而jQuery会向您显示委托的元素。 - Royi Namir