Backbone 视图事件在渲染不止一次时不起作用

Backbone views events not working when rendering more than once

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

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

所以...直到今天,它一直运行良好。在我的一个视图中,我调用了两次 render 函数。第一次调用 render 函数时,一切正常。事件按预期触发和捕获。但是,如果我第二次调用 render 函数,我的视图事件中的 none 将被触发。

这是我的视图模板:

  <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 元素,它们的事件侦听器也是如此……对吗?至少那是我所期待的,但似乎我错了。

非常欢迎对此有任何见解。在误入歧途之前,我想深入了解这里发生了什么。

非常感谢

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

Backbone documentation: "By default, delegateEvents is called within the View's constructor for you, so if you have a simple events hash, all of your DOM events will always already be connected, and you will never have to call this function yourself."

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