overriding Backbone.View delegateEvents so the events object can include mobile events

自闭症网瘾萝莉.ら 提交于 2019-12-13 02:42:58

问题


I am using Hammer.js to capture touchscreen events in a Backbone View. Hammer has a special syntax for adding touch listeners, which I have been using in the View's initialize function:

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

I would rather add it to the standard events object, like this:

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

So I hacked the end of Backbone.View's delegateEvents method:

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

        }

This works fine. But when I tried to override the method in the one View where it was needed the override (worried that I would forget about this hack in Backbone, or overwrite it with a new version of Backbone, etc.), delegateEvents for my View stopped working. The problem is that the method callback is not recognized as a method:

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

Why? I literally copy and pasted the function into the View subclass. Here is the whole delegateEvents that works in Backbone, but not in my 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:

Replace this line:

var match = key.match(delegateEventSplitter);

with this one:

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

回答1:


This jsbin shows how it is possible to override the default Backbone View logic for delegateEvents.

You can easily extend it as needed to handle Hammer.JS as you had above to extend Backbone to support the various touch events.

I needed to copy the value of delegateEventSplitter locally as it's privately declared (within a closure) inside of the Backbone library. Only functions that were executed/returned within the context of that variable are able to access that value. Since your new class does not execute in that context, it's unable to directly access the value.

The relevant code:

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


来源:https://stackoverflow.com/questions/16067989/overriding-backbone-view-delegateevents-so-the-events-object-can-include-mobile

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!