【问题标题】:AngularJs controller .appendChild() adding up each time view is visited每次访问视图时,AngularJs 控制器 .appendChild() 都会累加
【发布时间】:2017-01-28 18:40:52
【问题描述】:

我最近创建了一个聊天功能,我注意到一个奇怪的错误。以下是我在控制器中使用的代码:

    myFirebase.on('child_added', function(snapshot) {
    var msg = snapshot.val();
    var msgUsernameElement = document.createElement("b");
    msgUsernameElement.textContent = msg.user;

    var msgTextElement = document.createElement("p");
    msgTextElement.textContent = msg.message;

    var msgElement = document.createElement("div");
    msgElement.appendChild(msgUsernameElement);
    msgElement.appendChild(msgTextElement);

    document.getElementById("messages").append(msgElement);
  });

假设我们第一次进入 Chat 视图,然后当我聊天时,.appendChild() 工作得非常好,输入的消息显示在 div 'messages' 中。现在假设我们离开 Chat 视图并重新进入它,然后键入并发送另一条聊天消息,然后执行两次 .appendChild() 并且相同的消息在 div 'messages' 中出现两次。这会线性继续,因此如果我们第五次重新进入控制器并发送消息,则该消息将五次附加到 div 'messages' ...... 这是怎么回事?

我正在使用 Ionic 框架和现成的应用程序模板“标签”。我的聊天功能在聊天详细信息控制器中。

【问题讨论】:

    标签: javascript html angularjs ionic-framework firebase-realtime-database


    【解决方案1】:

    问题是因为事件处理程序被添加了两次,一次是在您第一次访问聊天页面时,另一次是在您返回时。要确认这一点,请第三次访问它,您应该会看到 3 次。

    解决方案是放入$onDestroy 处理程序以删除事件处理程序。如果无法删除事件处理程序(即它没有off 方法),那么您应该设置一个变量来告诉您它已初始化,并在初始化页面时检查它(以防止您这样做两次)

    【讨论】:

      【解决方案2】:

      因此,Mikkel 给出了正确的建议来初始化一个变量,并基本上将其用作一个标志,以确保我的事件处理程序不会被多次调用,给 Chat 视图的多个条目,但只调用一次。以下是我的解决方案:

          if (window.localStorage.getItem("notVisited") == null){ //This initilizes a variable in localstorage
               window.localStorage.setItem("notVisited","true");
          }
      
          var startListening = function() {
           myFirebase.on('child_added', function(snapshot) {
           var msg = snapshot.val();
           var msgUsernameElement = document.createElement("b");
           msgUsernameElement.textContent = msg.user;
      
           var msgTextElement = document.createElement("p");
           msgTextElement.textContent = msg.message;
      
           var msgElement = document.createElement("div");
           msgElement.appendChild(msgUsernameElement);
           msgElement.appendChild(msgTextElement);
      
           document.getElementById("messages").append(msgElement);
          });
          window.localStorage.setItem("notVisited","false");
         }
      if (window.localStorage.getItem("notVisited") == "true") {
          startListening();
      }
      

      现在实现这个之后,我遇到了一个新问题,即使用这个新代码,每次我重新进入视图时,以前的聊天消息都不会显示。所以我添加了这个:

              if (window.localStorage.getItem("notVisited") == "false"){
      $http({
          url: "https://uniff-f4136.firebaseio.com/" + chatKey + ".json",
          method: "GET"
          }).then(function (response) {
              for (var i in response.data){
                  var msgUsernameElement = document.createElement("b");
                  msgUsernameElement.textContent = response.data[i].user;
      
                  var msgTextElement = document.createElement("p");
                  msgTextElement.textContent = response.data[i].message;
      
                  var msgElement = document.createElement("div");
                  msgElement.appendChild(msgUsernameElement);
                  msgElement.appendChild(msgTextElement);
      
                  document.getElementById("messages").append(msgElement);
              }
          });
      }
      

      最后,虽然我不喜欢重复代码,但这使我的聊天工作正常进行。我希望其他人觉得这很有见地。 最后,要了解如何使用 firebase 构建实时网络聊天应用,请访问此 Google CodeLabs 链接:https://codelabs.developers.google.com/codelabs/cloud-firebase-chat/#4

      【讨论】:

      • 您可以通过获取通用代码并将其放入方法中来重构代码,只需注意将内容作为参数传递,您会是对的。您可能还想看看 Meteor (meteor.com),因为它是一个专为简单的反应式应用程序(如聊天)而设计的堆栈,您只需订阅数据,更改就会自动发送。
      猜你喜欢
      • 2019-07-15
      • 1970-01-01
      • 1970-01-01
      • 2014-11-12
      • 1970-01-01
      • 2022-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多