我有一个问题,我无法很好地理解Backbone视图事件。
几个星期前,我遇到了" multiple views events triggering"问题,因为我将所有视图元素附加到现有且永不压缩的DOM元素(我的页面架构中为#page_content
,见下文),并且我没有手动清理视图和事件)。
由于我不想手动进行清洁,不是懒惰,但因为我发现它容易出错,我最终得到了一个很好的解决方法,就是永远不要将我的观点附加到现有的DOM元素。因此,我只使用tagName
和className
来创建我的视图元素,然后将其插入到现有DOM元素中(通常在#page_content
内,见下文)。由于Backbone删除了事件监听器(如果它们所附着的DOM元素被删除),并且如果它们的元素从DOM中删除,垃圾收集视图,我发现这是处理视图及其事件的一种非常简洁的方法。
所以......直到今天,这一直很好。在我的一个视图中,我调用了两次render
函数。第一次调用render
函数时,一切正常。触发事件并按预期捕获。但是,如果我第二次调用render
函数,则不再触发任何视图事件。
以下是我的观点模板:
<script type="text/template" id="chat_selection_template">
<div class="push_me_down side_pad_me">
<div id="schools_chat_container">
<h2>Chat par école:</h2>
<ul>
<% if (schools) { %>
<% for (var i=0; i<schools.length; i++) { %>
<li class="school">
<a href="/chat/school/<%= schools[i].id %>" class="mlb_text blue">
<%= schools[i].attributes.appellation_officielle_uai %>Rejoindre ce chat
<i class="fa fa-chevron-right"></i>
</a>
</li>
<% } %>
<% } else { %>
<li class="empty">Vous n'êtes assigné(e) à aucune école pour le moment. <a class="mlb_text blue" href="/select_lines">Sélectionner une école à laquelle emmener vos enfants en Pédibus</a>.</li>
<% } %>
</ul>
</div>
<div id="lines_chat_container">
<h2>Chat par ligne:</h2>
<ul>
<% if (lines) { %>
<% for (var i=0; i<lines.length; i++) { %>
<li class="line"><%= lines[i].attributes.start_point_name %> - <%= lines[i].attributes.schoolName %> <a href="/chat/line/<%= lines[i].id %>" class="btn btn-mlb">Rejoindre ce chat</a></li>
<% } %>
<% } else { %>
<li class="empty">Vous n'êtes inscrit(e) à aucune ligne pour le moment. <a class="mlb_text blue" href="/select_lines">Inscrire mon enfant à une ligne de Pédibus</a>.</li>
<% } %>
</ul>
</div>
</div>
</script>
这是JS:
// Chat selection page View
MLB.ChatSelectionView = Parse.View.extend({
tagName: 'div',
className: 'chat_selection_container',
template: _.template($("#chat_selection_template", MLB.TEMPLATES).html()),
schools: false,
lines: false,
events : {
"click #select_school_link": "go_select_a_school",
},
initialize : function() {
var School = Parse.Object.extend("School");
var school_query = new Parse.Query(School);
var current_user = Parse.User.current();
var Line = Parse.Object.extend("Route");
var line_query = new Parse.Query(Line);
var self = this;
school_query.equalTo("parents", current_user);
school_query.find().then(
function(schools) {
if (schools.length > 0) {
self.schools = schools;
}
self.render();
},
function(error) {
MLB.log_to_parse("middle",'chat_selection', 'Failed to retrieve schools.');
self.render();
}
);
line_query.equalTo("contributors", current_user);
line_query.find().then(
function(lines) {
if (lines.length > 0) {
self.lines = lines;
}
self.render();
},
function(error) {
MLB.log_to_parse("middle",'chat_selection', 'Failed to retrieve lines.');
self.render();
}
);
},
go_select_a_school: function(event) {
event.preventDefault();
Parse.history.navigate("consult_lines", {trigger: true});
},
render : function(schools) {
this.$el.html( this.template({schools: this.schools, lines: this.lines}) );
MLB.CONTENT.html(this.$el);
},
});
这是我的应用HTML架构:
<html>
<head></head>
<body>
<div id="content-wrapper">
<header id="page_header">
<div class="wrapper">
<h1 class="logo">
<a href="/" id="header_homepage">PetitBus</a>
</h1>
<div id="header_login"></div>
</div>
</header>
<div id="fb-root"></div>
<div id="page_content"></div>
<!-- TEMPLATES -->
<div id="templates">
[Backbone templates code]
</div>
</body>
</html>
我想理解为什么第二次调用render
函数会搞砸所有问题。由于我对看到后面发生的事情的理解有限,所以当发生这种情况时,第一个渲染中的所有DOM元素都会被删除,他们的事件监听器也是如此。但随后插入了新的DOM元素,他们的事件监听器也是如此......对吗?至少这是我所期待的,但似乎我错了。
对此非常欢迎。我想在冲向错误的方向之前深刻理解这里发生了什么。
非常感谢
答案 0 :(得分:1)
添加this.delegateEvents();
作为渲染功能的最后一行。
Backbone文档:“默认情况下,在其中调用delegateEvents View的构造函数,所以如果你有一个简单的事件哈希, 您的所有DOM事件将始终已连接,您将会这样做 永远不必亲自调用此功能。“
因此,如果您第二次渲染视图,则需要自己调用delegateEvents,因为不会再次调用构造函数。