我创建了一堆Backbone.js次观看。每个视图都有一个关联元素(view.el
)。
给定页面上的元素 - 视图的上下文 - 获取元素视图的最佳方法是什么?
例如,假设某个事件会影响页面上的一堆元素,并且我想在与受影响元素关联的每个视图上调用一个方法。
一种方法是将视图分配给元素的数据,但我想知道我是否错过了更聪明的东西:
var myview = BackBone.View.extend({
initialize: function(options) {
$(this.el).data('view', this);
...
}
});
(我正在使用Backbone和jQuery 1.5。)
答案 0 :(得分:15)
我刚刚为此编写了一个jQuery插件。它还使用.data()
方法。
我已经包装/代理了Backbone View setElement
方法,以将所需数据附加到视图的$el
属性。
在幕后完成注册,如下所示:
$(myViewsEl).backboneView(myView);
插件遍历DOM层次结构(使用.closest()
),直到找到具有所需数据条目的元素,即具有关联视图的DOM元素:
var nearestView = $(e.target).backboneView();
此外,我们可以指定我们希望获得的Backbone View类型,继续层次结构,直到找到匹配类型的实例:
var nearestButtonView = $(e.target).backboneView(ButtonView);
可以找到here。
我希望我认为这里没有内存泄漏是正确的;如果第二次调用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);
答案 1 :(得分:6)
每个视图都可以注册DOM事件。因此,具有您感兴趣的元素类型的每个视图都应该注册DOM事件,然后分配一个事件响应函数来执行您想要的操作。如果您需要干预,请使用mixin技术混合功能。
我认为这个解决方案可能比您最初想象的要容易。只是让观点完成他们打算做的工作。
答案 2 :(得分:2)
您可以维护一个视图哈希(字典),它使用该元素作为键并返回视图(或视图)。
答案 3 :(得分:0)
由于每个视图都有对其显示的模型的引用,我要做的是将模型的id分配给视图的相关元素(希望不受外部事件更改的影响)。还要确保模型具有对其视图的引用。然后将这些模型存储在Backbone集合中。
使用此设置,一旦元素发生某些事情,您可以使用元素id从上面创建的Backbone集合中检索相应的模型,然后此模型将为您提供视图参考。
答案 4 :(得分:0)
我一直在使用受Ed's solution启发的方法,但它不需要使用jQuery。它做了两件事:
它在所有视图的根元素上设置属性data-backbone-view
。在调试器中查看DOM树时,这很方便。您可以立即查看哪些元素与视图相关联。您还可以使用CSS选择器[data-backbone-view]
来查找作为Backbone视图根源的元素。
它为视图的每个根元素添加backboneView
属性。然后可以通过查看DOM元素的属性从DOM元素到视图。
我只在我调试时打开它。这是代码:
var originalSetElement = Bb.View.prototype.setElement;
Bb.View.prototype.setElement = function setElement(element) {
if (this.el && this.el !== element) {
delete this.el.backboneView;
}
element.backboneView = this;
element.setAttribute("data-backbone-view", "true");
return originalSetElement.apply(this, arguments);
};