Javascript 在 Backbone.js 视图中动态设置 id 和 className
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7033134/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Setting id and className dynamically in Backbone.js views
提问by Nadav
I am in process of learning and using Backbone.js.
我正在学习和使用 Backbone.js。
I have an Item model and a corresponding Item view. Each model instance has item_class and item_id attributes, that I want to be reflected in as the 'id' and 'class' attributes of the corresponding view. What's the correct way to achieve this ?
我有一个 Item 模型和一个相应的 Item 视图。每个模型实例都有 item_class 和 item_id 属性,我希望将它们反映为相应视图的 'id' 和 'class' 属性。实现这一目标的正确方法是什么?
Example:
例子:
var ItemModel = Backbone.Model.extend({
});
var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});
var ItemView = Backbone.View.extend({
});
How should I implement the view so that the the views 'el's will translate to:
我应该如何实现视图,以便视图 el 将转换为:
<div id="id1" class="nice"></div>
<div id="id2" class="sad"> </div>
In most examples I have seen, the view's elserves as a meaningless wrapper element inside which one has to manually write the 'semantic' code.
在我见过的大多数示例中,视图的el充当无意义的包装元素,必须在其中手动编写“语义”代码。
var ItemView = Backbone.View.extend({
tagName: "div", // I know it's the default...
render: function() {
$(this.el).html("<div id="id1" class="nice"> Some stuff </div>");
}
});
So when rendered, one gets
所以当渲染时,一个人得到
<div> <!-- el wrapper -->
<div id="id1" class="nice"> Some stuff </div>
</div>
But this seems like a waste - why have the external div ? I want the elto translate directly into the internal div!
但这似乎是一种浪费-为什么要有外部 div ?我要el直接翻译成内部div!
回答by JMM
Summary: dynamically set view attributes with model data
总结:使用模型数据动态设置视图属性
// View class with `attributes` method
var View = Backbone.View.extend( {
attributes : function () {
// Return model data
return {
class : this.model.get( 'item_class' ),
id : this.model.get( 'item_id' )
};
}
// attributes
} );
// Pass model to view constructor
var item = new View( {
model : new Backbone.Model( {
item_class : "nice",
item_id : "id1"
} )
} );
This example assumes that you're allowing Backbone to generate a DOM element for you.
The
attributes
method is called after the properties passed to the view constructor are set (in this case,model
), allowing you to dynamically set the attributes with the model data before Backbone createsel
.In contrast to some of the other answers: doesn't hard-code attribute values in the view class, dynamically sets them from model data; doesn't wait until
render()
to set attr vals; doesn't repeatedly set attr vals in every call torender()
; doesn't unnecessarily manually set attr vals on DOM element.Note that if setting the class when calling
Backbone.View.extend
or a view constructor (e.g.new Backbone.View
), you have to use the DOM property name,className
, but if setting it via theattributes
hash / method (as in this example) you have to use the attribute name,class
.As of Backbone 0.9.9:
When declaring a View...
el
,tagName
,id
andclassName
may now be defined as functions, if you want their values to be determined at runtime.I mention this in case there's a situation where that would be useful as an alternative to using an
attributes
method as illustrated.
此示例假定您允许 Backbone 为您生成 DOM 元素。
attributes
在设置传递给视图构造函数的属性后调用该方法(在本例中为model
),允许您在 Backbone 创建之前使用模型数据动态设置属性el
。与其他一些答案相反:不在视图类中对属性值进行硬编码,而是从模型数据中动态设置它们;不等到
render()
设置 attr vals;不会在每次调用中重复设置 attr valsrender()
; 不会在 DOM 元素上不必要地手动设置 attr vals。请注意,如果在调用
Backbone.View.extend
或视图构造函数(例如new Backbone.View
)时设置类,则必须使用 DOM 属性名称className
,但如果通过attributes
哈希/方法(如本例中)设置它,则必须使用属性名称class
。从 Backbone 0.9.9 开始:
在声明 View...
el
、tagName
、id
和className
现在可以定义为函数时,如果您希望在运行时确定它们的值。我会提到这一点,以防在某些情况下这将作为使用
attributes
所示方法的替代方法很有用。
Using an existing element
使用现有元素
If you're using an existing element (e.g. passing el
to the view constructor)...
如果您使用现有元素(例如传递el
给视图构造函数)...
var item = new View( { el : some_el } );
...then attributes
won't be applied to the element. If the desired attributes aren't already set on the element, or you don't want to duplicate that data in your view class and another location, then you may want to add an initialize
method to your view constructor that applies attributes
to el
. Something like this (using jQuery.attr
):
...然后attributes
不会应用于元素。如果尚未在元素上设置所需的属性,或者您不想在视图类和其他位置复制该数据,那么您可能需要向initialize
视图构造函数添加一个适用attributes
于el
. 像这样(使用jQuery.attr
):
View.prototype.initialize = function ( options ) {
this.$el.attr( _.result( this, 'attributes' ) );
};
Usage of el
, rendering, avoiding the wrapper
的使用el
,渲染,避免包装器
In most examples I have seen, the view's el serves as a meaningless wrapper element inside which one has to manually write the 'semantic' code.
在我见过的大多数示例中,视图的 el 充当无意义的包装元素,必须在其中手动编写“语义”代码。
There's no reason view.el
needs to be "a meaningless wrapper element". In fact, that would often break the DOM structure. If a view class represents a <li>
element for example, it needs to be rendered as an <li>
-- rendering it as a <div>
or any other element would break the content model. You'll likely want to focus on correctly setting up your view's element (using properties like tagName
, className
, and id
) and then rendering its contentthereafter.
没有理由view.el
需要成为“无意义的包装元素”。事实上,这通常会破坏 DOM 结构。<li>
例如,如果视图类表示一个元素,则需要将其呈现为<li>
-- 将其呈现为 a<div>
或任何其他元素都会破坏内容模型。你可能会希望把重点放在如何正确设置视图的元素(使用类似的属性tagName
,className
和id
),然后渲染它的内容之后。
The options for how to have your Backbone view objects interact with the DOM are wide open. There are 2 basic initial scenarios:
如何让 Backbone 视图对象与 DOM 交互的选项是非常开放的。有两种基本的初始场景:
You can attach an existing DOM element to a Backbone view.
You can allow Backbone to create a new element that is disconnected from the document, then somehow insert it into the document.
您可以将现有的 DOM 元素附加到 Backbone 视图。
您可以允许 Backbone 创建一个与文档断开连接的新元素,然后以某种方式将其插入到文档中。
There are various ways you can generate the content for the element (set a literal string, as in your example; use a templating library like Mustache, Handlebars, etc.). How you should use the el
property of the view depends what you're doing.
有多种方法可以为元素生成内容(设置文字字符串,如您的示例;使用模板库,如 Mustache、Handlebars 等)。您应该如何使用el
视图的属性取决于您在做什么。
Existing element
现有元素
Your rendering example suggests that you have an existing element that you're assigning to the view, although you don't show instantiation of the views. If that's the case, and the element is already in the document, then you may want to do something like this (update the content of el
, but don't alter el
itself):
您的渲染示例表明您有一个要分配给视图的现有元素,尽管您没有显示视图的实例化。如果是这种情况,并且该元素已经在文档中,那么您可能想要做这样的事情(更新 的内容el
,但不要改变el
自己):
render : function () {
this.$el.html( "Some stuff" );
}
Generated element
生成元素
Let's say you don't have an existing element and you allow Backbone to generate one for you. You maywant to do something like this (but it's likely better to architect things so that your view isn't responsible for knowing about anything outside itself):
假设您没有现有元素,并且您允许 Backbone 为您生成一个。您可能想要做这样的事情(但架构事物可能会更好,以便您的视图不负责了解自身之外的任何事情):
render : function () {
this.$el.html( "Some stuff" );
$( "#some-container" ).append( this.el );
}
Templates
模板
In my case, I'm using templates, e.g.:
就我而言,我正在使用模板,例如:
<div class="player" id="{{id}}">
<input name="name" value="{{name}}" />
<input name="score" value="{{score}}" />
</div>
<!-- .player -->
The template represents the complete view. In other words, there will be no wrapper around the template -- div.player
will be the root or outermost element of my view.
模板代表完整的视图。换句话说,模板周围没有包装器——div.player
将是我的视图的根元素或最外层元素。
My player class will look something like this (with very simplified example of render()
):
我的播放器类将如下所示(使用非常简化的 示例render()
):
Backbone.View.extend( {
tagName : 'div',
className : 'player',
attributes : function () {
return {
id : "player-" + this.model.cid
};
},
// attributes
render : function {
var rendered_template = $( ... );
// Note that since the top level element in my template (and therefore
// in `rendered_template`) represents the same element as `this.el`, I'm
// extracting the content of `rendered_template`'s top level element and
// replacing the content of `this.el` with that.
this.$el.empty().append( rendered_template.children() );
}
} );
回答by Dan Brooke
In your view just do something like this
在你看来只是做这样的事情
var ItemView = Backbone.View.extend({
tagName: "div", // I know it's the default...
render: function() {
$(this.el).attr('id', 'id1').addClass('nice').html('Some Stuff');
}
});
回答by J?rgen
You can set the properties className
and id
on the root element:
http://documentcloud.github.com/backbone/#View-extend
您可以设置属性className
和id
根元素:
http://documentcloud.github.com/backbone/#View-extend
var ItemView = Backbone.View.extend({
tagName: "div", // I know it's the default...
className : 'nice',
id : 'id1',
render: function() {
$(this.el).html("Some stuff");
}
});
EDITIncluded example of setting id based on constructor parameters
编辑包括基于构造函数参数设置 id 的示例
If the views are constructed as mentioned:
如果按照上述方式构建视图:
var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});
Then the values could be set this way:
然后可以这样设置值:
// ...
className: function(){
return this.options.item_class;
},
id: function(){
return this.options.item_id;
}
// ...
回答by Marcus
I know it's an old question, but added for reference. This seems to be easier in new backbone versions. In Backbone 1.1 the id and className properties are evaluated in the function ensureElement
(see from source) using underscore _.result
meaning if className
or id
is a function, it will be called, otherwise its value will be used.
我知道这是一个老问题,但已添加以供参考。这在新的主干版本中似乎更容易。在 Backbone 1.1 中, id 和 className 属性在函数中使用下划线进行评估ensureElement
(参见源代码),这_.result
意味着如果className
或者id
是一个函数,它将被调用,否则将使用它的值。
So you could give className directly in the constructor, give another parameter that would be used in the className, etc... Plenty of options
所以你可以直接在构造函数中给出 className,给出另一个将在 className 中使用的参数,等等......很多选项
so this should work
所以这应该有效
var item1 = new ItemModel({item_class: "nice", item_id: "id1"});
var item2 = new ItemModel({item_class: "sad", item_id: "id2"});
var ItemView = Backbone.View.extend({
id: function() { return this.model.get('item_id'); },
className: function() { return this.model.get('item_class'); }
});
回答by diskodave
The other examples are not showing how to actually grab the data from the model. To dynamically add id and class from the model's data:
其他示例并未展示如何从模型中实际获取数据。要从模型的数据中动态添加 id 和 class:
var ItemView = Backbone.View.extend({
tagName: "div",
render: function() {
this.id = this.model.get('item_id');
this.class = this.model.get('item_class');
$(this.el).attr('id',this.id).addClass(this.class).html('Some Stuff');
}
});
回答by jskulski
You need to remove tagName and declare an el.
您需要删除 tagName 并声明一个 el。
'tagName' signifies that you want backbone to create an element. If the element already exists in the DOM, you can specify an el like:
'tagName' 表示您希望主干创建一个元素。如果元素已经存在于 DOM 中,你可以指定一个 el,如:
el: $('#emotions'),
and later:
然后:
render: function() {
$(this.el).append(this.model.toJSON());
}
回答by Hemanth
Try to assign the values in initialize method this will directly assign id and class to the div attribute dynamically.
尝试在 initialize 方法中分配值,这将直接动态地将 id 和 class 分配给 div 属性。
var ItemView = Backbone.View.extend( {
tagName : "div",
id : '',
class : '',
initialize : function( options ) {
if ( ! _.isUndefined( options ) ) {
this.id = options.item_id;
this.class= options.item_class;
}
},
render : function() {
$( this.el ).html( this.template( "stuff goes here" ) );
}
} );
回答by Emile Bergeron
Here's a minimal way to change the class of the view's element dynamically via a model and update it on model changes.
这是通过模型动态更改视图元素的类并在模型更改时更新它的最小方法。
var VMenuTabItem = Backbone.View.extend({
tagName: 'li',
events: {
'click': 'onClick'
},
initialize: function(options) {
// auto render on change of the class.
// Useful if parent view changes this model (e.g. via a collection)
this.listenTo(this.model, 'change:active', this.render);
},
render: function() {
// toggle a class only if the attribute is set.
this.$el.toggleClass('active', Boolean(this.model.get('active')));
this.$el.toggleClass('empty', Boolean(this.model.get('empty')));
return this;
},
onClicked: function(e) {
if (!this.model.get('empty')) {
// optional: notify our parents of the click
this.model.trigger('tab:click', this.model);
// then update the model, which triggers a render.
this.model.set({ active: true });
}
}
});