多次渲染时,Backbone 视图事件不起作用

Posted

技术标签:

【中文标题】多次渲染时,Backbone 视图事件不起作用【英文标题】:Backbone views events not working when rendering more than once 【发布时间】:2015-05-30 19:47:05 【问题描述】:

我有一个问题,我无法很好地理解 Backbone 视图事件。 几周前,我遇到了“multiple views events triggering”问题,因为我将所有视图元素附加到一个现有且从未抑制的 DOM 元素(我的页面架构中的#page_content,见下文),而我没有t 手动清理视图和事件)。

因为我不想手动进行清理,不是因为懒惰,而是因为我发现它容易出错,所以我最终找到了一个很好的解决方法,即永远不要将我的视图附加到现有 DOM元素。所以我只使用tagNameclassName 来创建我的视图元素,然后我将其插入到现有的DOM 元素中(通常是在#page_content 中,见下文)。由于 Backbone 会在它们附加到的 DOM 元素被删除时删除事件侦听器,并且如果它们的元素从 DOM 中删除,也会对 Views 进行垃圾收集,我发现这是一种处理 Views 及其事件的非常干净和简单的方法。

所以...直到今天它一直运行良好。在我的一个视图中,我调用了两次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 元素,它们的事件侦听器也是如此……对吗?至少这是我所期待的,但似乎我错了。

非常欢迎对此的任何见解。我想深入了解这里发生的事情,然后再朝错误的方向前进。

非常感谢

【问题讨论】:

两次调用render是指代码中的两次调用。一个在school_query的回调中,另一个在lines_query的回调中? 感谢您的回复。是的,我的意思是这两个电话。我这样做,所以我可以更快地向用户输出一些东西,并在第二个回调的信息返回时完成视图。你觉得这里有什么问题吗? 【参考方案1】:

添加this.delegateEvents(); 作为渲染函数的最后一行。

Backbone 文档:“默认情况下,delegateEvents 在 视图的构造函数,所以如果你有一个简单的事件哈希, 您的所有 DOM 事件将始终已连接,并且您将 永远不必自己调用这个函数。”

因此,如果您再次渲染视图,则需要自己调用 delegateEvents,因为不会再次调用构造函数。

【讨论】:

罗杰。我知道delegateEvents,但不太了解它在做什么。有了这个案例和你的解释,现在就一清二楚了。谢谢!

以上是关于多次渲染时,Backbone 视图事件不起作用的主要内容,如果未能解决你的问题,请参考以下文章

j渲染视图后Javascript不起作用

Backbone.js — 匿名视图实例中的集合在获取时多次请求

当位置为绝对时,onPress 事件在动画视图中不起作用

当尝试从带有点击事件的视图滚动时,滚动在 NestedScrollView 中不起作用

UITableViewCell 背景渐变在第一次渲染时不起作用

使用布局渲染 gsp / 视图不起作用