我有一些不同的问题,我希望这个例子很容易理解。该代码使用HTML模板,默认情况下隐藏了元素(使用CSS)。 Backbone View使用Model中的数据显示适当的值,或者如果模式中没有值,则隐藏UI元素。
给定一个默认隐藏所有内容的模板(使用CSS),例如:
<script type="text/template" id="Person-Template">
<span class="fname" title="FirstName"></span>
<span class="lname" title="LastName"></span>
<span class="age" title="Age"></span>
</script>
隐藏CSS的每个UI元素:
span.fname,
span.lname,
span.age {
display:none;
}
我的Backbone.js模型因此是:
PersonModel = Backbone.Model.extend({
defaults: {
fname: undefined,
lname: undefined,
age: undefined
}
});
View(简化)将是:
PersonView = Backbone.View.extend({
tagName: 'div',
initialize: function() {
this.model.on("fname", this.updateFName, this);
this.model.on("lname", this.updateLName, this);
this.model.on("age", this.updateAge, this);
},
updateFName: function() {
// Pseudo code
Get 'new' value from Model
Obtain reference to DOM element span.fname
Update span.fname
if (model value is empty) {
Hide UI element.
}
},
updateLName: function() {
// Same as above
},
updateAge: function() {
// Same as above
},
render: function() {
// Get model values to display
var values = {
FirstName : this.model.get('fname'),
LastName : this.model.get('lname'),
Age: this.model.get('age'),
};
// Load HTML template
var template = $('#Person-Template').html();
// Populate template with values
var t = _.template(template, values);
// Show / hide UI elements
this.updateFname();
this.updateLName();
this.updateAge();
}
}
最后,问题是:看起来hacky从render()调用每个updateXYZ()方法只是为了确定UI元素是应该设置为隐藏还是可见。我的模型中有很多属性,代码看起来有点荒谬。
I have been told on SO视图不应该负责确定应该或应该显示什么。我的问题是,那么责任是什么?用户可以执行一些清除名字的(有效)aciton,在这种情况下,我不希望我的View显示“First name:”,后面没有值。
答案 0 :(得分:3)
首先,您不需要手动构建values
,只需使用toJSON
:
var values = this.model.toJSON();
然后,您必须将填好的模板添加到视图的el
:
this.$el.html(_.template(template, values));
,您的模板应该包含要在模板中显示的内容:
<script type="text/template" id="Person-Template">
<span class="fname" title="FirstName">F: <%= fname %></span>
<span class="lname" title="LastName">L: <%= lname %></span>
<span class="age" title="Age">A: <%= age %></span>
</script>
您不会为这三个部分中的每个部分分开功能,您可以在render
中循环使用它们:
_(values).each(function(v, k) {
var m = _(v).isUndefined() ? 'hide' : 'show';
this.$('.' + k)[m]();
}, this);
现在回到你的活动。除非您添加了自定义事件,否则不存在"fname"
事件。但是没有必要,当"change"
发生变化时,模型会触发"change:fname"
和fname
个事件;你只需要关心"change"
:
initialize: function() {
_.bindAll(this, 'render');
this.model.on("change", this.render);
},
我还使用_.bindAll
将render
绑定到您的视图实例,这样您就不必担心this.model.on
的第三个参数了。
现在你有一些有用的东西:http://jsfiddle.net/ambiguous/46puP/
您还可以将“应该显示”逻辑推送到模板中:
<script type="text/template" id="Person-Template">
<% if(fname) { %><span class="fname" title="FirstName">F: <%= fname %></span><% } %>
<% if(lname) { %><span class="lname" title="LastName">L: <%= lname %></span><% } %>
<% if(age) { %><span class="age" title="Age">A: <%= age %></span><% } %>
</script>
并简化您的render
:
render: function() {
var values = this.model.toJSON();
var template = $('#Person-Template').html();
this.$el.html(_.template(template, values));
return this;
}
演示:http://jsfiddle.net/ambiguous/W9cnJ/
这种方法可能是最常见的,并且没有任何问题。我认为你误解了之前的答案试图告诉你的内容。模板选择通过<%= ... %>
显示哪些信息,因此没有充分的理由在尝试显示之前不应该看到fname
是否已设置。根据数据的性质,您可能希望在模板中使用if(!_(fname).isUndefined())
等,但简单的真实性检查可能没问题;在某些情况下,age
可能会成为一个问题,所以你可能希望对此更加严格。