最重要的支柱.查看delegateEvents以便事件对象可以包含移动事件



我使用Hammer.js在骨干视图中捕获触摸屏事件。Hammer有一个特殊的语法来添加触摸监听器,我一直在视图的初始化函数中使用:

$("#next-button").hammer({prevent_default: true}).on('tap', $.proxy(this.next, this));

我宁愿把它添加到标准事件对象中,像这样:

events: {"tap #next-button":"next"}

所以我砍断了主干的末端。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);
            }
        }

这很好。但是,当我试图在一个视图中重写需要重写的方法时(担心我会忘记Backbone中的这个hack,或者用新版本的Backbone重写它,等等),我的视图的delegateEvents停止工作。问题是方法回调不能被识别为方法:

if (!_.isFunction(method)) method = this[events[key]];

为什么?我将函数复制粘贴到View子类中。下面是整个在主干中工作的delegateEvents,但不是在我的主干中。观点:

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);
            }
        }
      }

解决办法:

替换这一行:

var match = key.match(delegateEventSplitter);

和这个:

var match = key.match(/^(S+)s*(.*)$/);

这个jsbin显示了如何为delegateEvents覆盖默认的主干View逻辑。

你可以很容易地根据需要扩展它来处理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);  
});

最新更新