Backbone.js - Given an element, how do I get the view?

后端 未结 5 1798
刺人心
刺人心 2020-12-15 03:33

I\'ve created a bunch of Backbone.js views. Each view has an associated element (view.el).

Given an element on the page — out of context of the view — w

5条回答
  •  醉梦人生
    2020-12-15 04:15

    I've just written a jQuery plugin for this. It also uses the .data() method.

    Registration:

    I have wrapped / proxied the Backbone View setElement method to attach the required data to the view's $el property.

    Registration is done behind the scenes like so:

    $(myViewsEl).backboneView(myView);
    

    Retrieval:

    The plugin traverses up the DOM hierarchy (using .closest()) until it finds an element with the required data entry, i.e a DOM element with an associated view:

    var nearestView = $(e.target).backboneView();
    

    In addition, we can specify what type of Backbone View we wish to obtain, continuing up the hierarchy until we find an instance of matching type:

    var nearestButtonView = $(e.target).backboneView(ButtonView);
    

    JSFiddle Example:

    Can be found here.

    Notes:

    I hope I am correct in thinking there are no memory leaks involved here; An 'unlink' is performed if setElement is called a second time round, and since removing a view's element calls .remove() by default, which destroys all data as well. Let me know if you think differently.

    The plugin code:

    (function($) {
    
        // Proxy the original Backbone.View setElement method:
        // See: http://backbonejs.org/#View-setElement
    
        var backboneSetElementOriginal = Backbone.View.prototype.setElement;
    
        Backbone.View.prototype.setElement = function(element) {
            if (this.el != element) {
                $(this.el).backboneView('unlink');                    
            }
    
            $(element).backboneView(this);    
    
            return backboneSetElementOriginal.apply(this, arguments);
        };
    
        // Create a custom selector to search for the presence of a 'backboneView' data entry:
        // This avoids a dependency on a data selector plugin...
    
        $.expr[':'].backboneView = function(element, intStackIndex, arrProperties, arrNodeStack) {
            return $(element).data('backboneView') !== undefined;        
        };
    
        // Plugin internal functions:
    
        var registerViewToElement = function($el, view) {
            $el.data('backboneView', view);
        };
    
        var getClosestViewFromElement = function($el, viewType) {
            var ret = null;
    
            viewType = viewType || Backbone.View;
    
            while ($el.length) {
                $el = $el.closest(':backboneView');
                ret = $el.length ? $el.data('backboneView') : null;
    
                if (ret instanceof viewType) {
                    break;
                }
                else {
                    $el = $el.parent();
                }           
            }
    
            return ret;                
        };
    
        // Extra methods:
    
        var methods = {
    
            unlink: function($el) {
                $el.removeData('backboneView');        
            }
    
        };
    
        // Plugin:
    
        $.fn.backboneView = function() {
            var ret = this;
            var args = Array.prototype.slice.call(arguments, 0);
    
            if ($.isFunction(methods[args[0]])) {
                methods[args[0]](this);                        
            }
            else if (args[0] && args[0] instanceof Backbone.View) {
                registerViewToElement(this.first(), args[0]);                
            }
            else {
                ret = getClosestViewFromElement(this.first(), args[0]);
            }
    
            return ret;        
        }        
    
    })(jQuery);
    

提交回复
热议问题