我正在使用Hammer.js在Backbone View中捕获触摸屏事件。 Hammer有一个特殊的语法来添加触摸侦听器,我一直在View的初始化函数中使用它:
$("#next-button").hammer({prevent_default: true}).on('tap', $.proxy(this.next, this));
我宁愿将它添加到标准事件对象中,如下所示:
events: {"tap #next-button":"next"}
所以我攻击了Backbone.View的delegateEvents方法结束:
var isMobileEvent=["tap", "doubleTap"].indexOf(eventName)!=-1;
if (selector === '') {
if (isMobileEvent){
this.$el.hammer({prevent_default: true}).on(eventName, method);
} else {
this.$el.on(eventName, method);
}
} else {
if (isMobileEvent){
this.$el.hammer({prevent_default: true}).on(eventName, selector, method);
} else {
this.$el.on(eventName, selector, method);
}
}
这很好用。但是,当我试图在一个View中覆盖该方法时,需要覆盖(担心我会忘记Backbone中的这个hack,或用新版本的Backbone覆盖它等),我的View的delegateEvents停止工作。问题是方法回调不被识别为方法:
if (!_.isFunction(method)) method = this[events[key]];
为什么呢?我实际上将该函数复制并粘贴到View子类中。这是在Backbone中工作的整个delegateEvents,但不在我的Backbone.View中:
delegateEvents: function(events) {
if (!(events || (events = _.result(this, 'events')))) return;
this.undelegateEvents();
for (var key in events) {
var method = events[key];
if (!_.isFunction(method)) method = this[events[key]];
if (!method) throw new Error('Method "' + events[key] + '" does not exist');
var match = key.match(delegateEventSplitter);
var eventName = match[1], selector = match[2];
method = _.bind(method, this);
eventName += '.delegateEvents' + this.cid;
var isMobileEvent=["tap", "doubleTap"].indexOf(eventName)!=-1;
if (selector === '') {
if (isMobileEvent){
this.$el.hammer({prevent_default: true}).on(eventName, method);
} else {
this.$el.on(eventName, method);
}
} else {
if (isMobileEvent){
this.$el.hammer({prevent_default: true}).on(eventName, selector, method);
} else {
this.$el.on(eventName, selector, method);
}
}
}
THE FIX:
替换此行:
var match = key.match(delegateEventSplitter);
这一个:
var match = key.match(/^(\S+)\s*(.*)$/);
答案 0 :(得分:1)
此jsbin显示了如何覆盖View
的默认Backbone delegateEvents
逻辑。
您可以根据需要轻松扩展它,以便像上面一样处理Hammer.JS,以扩展Backbone以支持各种触摸事件。
我需要在本地复制delegateEventSplitter
的值,因为它是在Backbone库中私下声明的(在一个闭包内)。只有在该变量的上下文中执行/返回的函数才能访问该值。由于您的新类不在该上下文中执行,因此无法直接访问该值。
相关代码:
var SampleView = Backbone.View.extend({
events: {
"click" : '_clicked'
},
delegateEvents: function(events) {
if (!(events || (events = _.result(this, 'events')))) return;
this.undelegateEvents();
for (var key in events) {
var method = events[key];
if (!_.isFunction(method)) method = this[events[key]];
if (!method) throw new Error('Method "' + events[key] + '" does not exist');
var match = key.match(/^(\S+)\s*(.*)$/);
var eventName = match[1], selector = match[2];
method = _.bind(method, this);
eventName += '.delegateEvents' + this.cid;
if (selector === '') {
this.$el.on(eventName, method);
} else {
this.$el.on(eventName, selector, method);
}
}
},
render: function() {
this.$el.html("hi");
return this;
},
_clicked: function() {
alert("clicked!");
}
});
// assumes there's an element with an id of "content"
$(function() {
var view = new SampleView();
$("#content").append(view.render().$el);
});