Backbone.js - 给定一个元素,我如何获得视图?

a p*_*erd 31 javascript jquery backbone.js

我创建了一堆Backbone.js视图.每个视图都有一个关联的元素(view.el).

给定页面上的元素 - 视图的上下文 - 获取元素视图的最佳方法是什么?

例如,假设某些事件影响页面上的一堆元素,并且我想在与受影响元素关联的每个视图上调用方法.

一种方法是将视图分配给元素的数据,但我想知道我是否错过了更聪明的东西:

var myview = BackBone.View.extend({
    initialize: function(options) {
        $(this.el).data('view', this);
        ...
    }
});
Run Code Online (Sandbox Code Playgroud)

(我正在使用Backbone和jQuery 1.5.)

Ed *_*d . 15

我刚刚为此编写了一个jQuery插件.它也使用该.data()方法.

注册:

我已经包装/代理了Backbone View setElement方法,以将所需数据附加到视图的$el属性.

注册是在幕后完成的,如下所示:

$(myViewsEl).backboneView(myView);
Run Code Online (Sandbox Code Playgroud)

恢复:

插件遍历DOM层次结构(使用.closest()),直到找到具有所需数据条目的元素,即具有关联视图的DOM元素:

var nearestView = $(e.target).backboneView();
Run Code Online (Sandbox Code Playgroud)

另外,我们可以指定我们希望获得哪种类型的Backbone View,继续层次结构,直到找到匹配类型的实例:

var nearestButtonView = $(e.target).backboneView(ButtonView);
Run Code Online (Sandbox Code Playgroud)

JSFiddle示例:

可以在这里找到.

笔记:

我希望我认为这里没有内存泄漏是正确的; 如果setElement被称为第二轮,则执行'unlink' ,并且因为.remove()默认情况下删除视图的元素调用,这也会破坏所有数据.如果您有不同的想法,请告诉我.

插件代码:

(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);
Run Code Online (Sandbox Code Playgroud)


Bil*_*uer 6

每个视图都可以注册DOM事件.因此,具有您感兴趣的元素类型的每个视图都应该注册DOM事件,然后分配一个事件响应函数来执行您想要的操作.如果您需要干预,请使用mixin技术混合功能.

我想这个解决方案可能比你最初想象的要容易.只是让视图完成他们打算做的工作.

  • 使用一长串DOM元素,使用事件委托来捕获DOM事件通常更有效.在这种情况下,视图可能不知道从其关联元素调度的事件,因为事件是通过某些父视图在冒泡链上进一步捕获的.在这种情况下,您需要父视图来跟踪子视图元素,并在捕获事件时匹配它们. (3认同)
  • 这个答案的一个具有挑战性的场景是,您在视图范围内保存一堆数据,然后允许用户修改并拖放整个地方的元素,例如,在不同列表之间移动项目.然后在最后,您需要查询项目列表以获取其元素,将其转换为视图,从视图中返回复杂数据对象,并将所有内容作为JSON发送到服务器.在这种情况下,您几乎必须将某些内容与.data()相关联. (2认同)