[英]Event delegation with Hammer.js
How would I do jQuery-style event delegation with plain JavaScript in Hammer.js? 如何在Hammer.js中使用纯JavaScript进行jQuery样式的事件委派? Eg:
例如:
Hammer(document).on('tap', '.item', function () {
console.log('tapped')
})
Is this directly possible or do I have to do the delegation myself? 这是直接可能还是我自己必须做代表团?
I use the following function to test if the target is a delegate. 我使用以下函数来测试目标是否是委托。
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;
}
I'm using the jquery filter because I use it a lot and with some more complex selectors. 我正在使用jquery过滤器,因为我经常使用它和一些更复杂的选择器。
Usage: 用法:
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
}
});
This won't work with all selectors, but I'd say it's better than André's in that it will still work if your "target" has child elements. 这不适用于所有选择器,但我认为它比André更好,因为如果你的“目标”具有子元素,它仍然可以工作。 Eg
例如
<div id="parent">
<div class="child">
<div class="text">Test</div>
</div>
</div>
André's will fail here because target
is the [div.text]
and doesn't have your class. 安德烈将在这里失败,因为
target
是[div.text]
而没有你的班级。
For the above usage of _getDelegate, lets' say $element = $("#parent")
. 对于_getDelegate的上述用法,让我们说'
$element = $("#parent")
。 If you tapped the word "Test" event.target
would be [div.text]
(where you tapped) and event.currentTarget
would be [div.parent]
(where the handler is registered). 如果您点击了“Test”一词
event.target
将是[div.text]
(您点击的地方),而event.currentTarget
将是[div.parent]
(处理程序已注册)。 When you called _getDelegate
with these parameters, you would receive [div.child]
and know that you should run your handler code. 当您使用这些参数调用
_getDelegate
时,您将收到[div.child]
并知道您应该运行处理程序代码。
For a pure JS version, you'd want something like this, where you loop up through the parents looking to see if you hit anything. 对于一个纯粹的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');
}
There are still plenty of flaws with this. 这还有很多瑕疵。 The whole indexof className is a bad idea because classes can be sub-strings of one another eg "myClass" and "myClass2".
className的整个索引是一个坏主意,因为类可以是彼此的子字符串,例如“myClass”和“myClass2”。 Also, my code makes the assumption that all of your subelements are positioned within their parents.
此外,我的代码假设您的所有子元素都位于其父元素中。
Inspired by Jools' answer, here is what I've come up with. 灵感来自Jools的回答,这就是我想出的。 I didn't bother with a pure-JS solution--in fact, this is intended for use with a
Backbone.View
, but is easily adaptable to other situations. 我没有使用纯JS解决方案 - 实际上,这是用于
Backbone.View
,但很容易适应其他情况。
It will stop climbing the node tree when it reaches the View's root element ( this.el
). 当它到达View的根元素(
this.el
)时,它将停止攀爬节点树。 Starting from the target identified by the HammerJS event, it will seek the first element matching the specified selector, and return undefined
if no such element is found. 从HammerJS事件标识的目标开始,它将寻找与指定选择器匹配的第一个元素,如果没有找到这样的元素,则返回
undefined
。
To use in a non-Backbone environment, just pass in a reference to the limiting/containing element as a 3rd argument (as in Jools' solution) and use it to replace this.el
. 要在非Backbone环境中使用,只需
this.el
元素的引用作为第三个参数传递(如在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;
}
If you have an onTap
callback function, it might look something like this: 如果你有一个
onTap
回调函数,它可能看起来像这样:
/**
* @param {Event}ev
*/
onTap: function (ev) {
var target = this.getEventDelegate(ev.target, "#desiredTarget");
if (target) {
// TODO something with the target...
}
}
And to hook it all up, you'd want something like this... 把它全部搞定,你想要这样的东西......
this._hammer = new Hammer(this.el);
this._hammer.on('tap', _.bind(this.onTap, this));
(and don't forget to call this._hammer.destroy()
when your view is destroyed!) (当你的视图被销毁时别忘了调用
this._hammer.destroy()
!)
You simply need to inspect the target
of the Event object that's passed into your handler. 您只需要检查传递给处理程序的Event对象的
target
。
Here's a demo . 这是一个演示 。
Continuing @Lambarr's solution - Typescript: 继续@ 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);
}
}
Usage : 用法:
private registerDocumentclick()
{
Hammer(this.document).on('tap', e =>
this.delegateBind(this.document,e,'.article', (elm) => console.log(elm.classList))
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.