admin管理员组文章数量:1315344
How would I do jQuery-style event delegation with plain JavaScript in Hammer.js? E.g.:
Hammer(document).on('tap', '.item', function () {
console.log('tapped')
})
Is this directly possible or do I have to do the delegation myself?
How would I do jQuery-style event delegation with plain JavaScript in Hammer.js? E.g.:
Hammer(document).on('tap', '.item', function () {
console.log('tapped')
})
Is this directly possible or do I have to do the delegation myself?
Share Improve this question asked Jul 26, 2013 at 11:15 SachaSacha 2,8343 gold badges23 silver badges27 bronze badges 2-
Inspecting target - will only work if you click on element with
.item
. But if inside that.item
there is another element and you click on that inner element - inspecting target will NOT help. you'd need to scan its parent (which is what other answers provided) - which exactly what you wanted in your question$.on('tap', '.item', function () {...}
. with jquery - using your code in question , you will be provided with the right info EVEN if you clicked in an inner element to.item
– Royi Namir Commented Apr 18, 2017 at 11:32 -
As you can see here - inspecting target will show you the button which is not
.item
jsbin./hobenunale/1/edit?html,js,output - while jquery does show you the delegeated element. – Royi Namir Commented Apr 18, 2017 at 11:44
4 Answers
Reset to default 3Inspired by Jools' answer, here is what I've e up with. 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.
It will stop climbing the node tree when it reaches the View's root element (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.
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
.
/**
* @param {Node}target - the target of the received event
* @param {String}selector - any jQuery-patible 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:
/**
* @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!)
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 plex selectors.
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. E.g.
<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.
For the above usage of _getDelegate, lets' say $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). When you called _getDelegate
with these parameters, you would receive [div.child]
and know that you should run your handler code.
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.
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 e.g. "myClass" and "myClass2". Also, my code makes the assumption that all of your subelements are positioned within their parents.
You simply need to inspect the target
of the Event object that's passed into your handler.
Here's a demo.
Continuing @Lambarr's solution - 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))
);
}
本文标签: javascriptEvent delegation with HammerjsStack Overflow
版权声明:本文标题:javascript - Event delegation with Hammer.js - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741976516a2408155.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论