让jQuery timeago插件识别新加载的DOM元素

5
我在我的Rails 3应用程序中使用jquery timeago插件。我在我的posts#show视图上有一个评论部分,它使用Railscasts第229集“轮询变化”中使用的AJAX每30秒自动刷新。由jQuery加载的_comment partial包含评论的created_at时间,该时间使用timeago Rails helper方法创建具有正确时间格式的attr标签。
当提交评论并使用ajax加载评论时,jQuery timeago插件无法识别新评论DOM元素。因此,评论的时间显示为“2010-11-21 23:08:36 UTC”,而不是“大约一分钟前”。
当然,我已经搜索了这个问题,并找到了关于使用.live()、.delegate()或livequery插件的建议。
comments/index.js.erb:
<% unless @comments.empty? %>
  $("#comments").append("<%=raw escape_javascript(render(@comments)) %>").timeago();
<% end %>

comments/show.js.erb:

$("#comments").append("<%=raw escape_javascript(render(@comments)) %>");

public/javascripts/application.js:

$(function() {
  if ($("#comments").length > 0) {
    setTimeout(updateComments, 30000);
  }
});

function updateComments () {
  var post_id = $("#post").attr("data-id");
  if ($("#comments").length > 0) {
    var after = $(".comment:last-child").attr("data-time");
  } else {
    var after = "0";
  }
  $.getScript("/posts/" + post_id + "/comments?after=" + after)
  setTimeout(updateComments, 30000);
}

helpers/application_help.rb:

module ApplicationHelper
  def timeago(time, options = {})
    options[:class] ||= "timeago"
    content_tag(:abbr, time.to_s, options.merge(:title => time.getutc.iso8601)) if time
  end
end

layouts/application.html.erb:

<!DOCTYPE html>
<html>
  <head>
    <%= stylesheet_link_tag 'style' %>
    <%= javascript_include_tag :defaults %>
    <%= javascript_include_tag 'jquery.timeago' %>
    <%= csrf_meta_tag %>
  </head>
  <body>
    <!-- ... -->
    <script type="text/javascript">
      $("abbr.timeago").timeago();
    </script>
  </body>
</html>

comments/_comment.html.erb:

<div class="comment" data-time="<%= comment.created_at.to_i %>">
  <%- if comment.commenter.empty? -%>
  <%- else -%>   
    <span class="name">
      <%- if comment.email.blank? -%>
        <%= comment.commenter %>:
      <%- else -%>
        <a href="mailto:<%= comment.email %>"><%= comment.commenter %>:</a>
      <%- end -%>
    </span>
  <%- end -%>

  <%= simple_format @comment.body %>

  <span class="time">
    <%= timeago(comment.created_at) %>
  </span>
</div>

posts/show.html.erb:

<div id="post" data-id="<%= @post.id %>">
  <%= link_to @post.title, @post %>
  <%= simple_format @post.content %>

  <% unless @post.comments.empty? %>
    <div id="comments">
      <%= render @post.comments %>
    </div>
  <% end %>
</div>

<div id="replyform">
  <%= render "comments/form" %>
</div>

AJAX轮询和timeago插件在其他地方都正常工作,只有当我在另一个浏览器中使用AJAX发表评论时,才会遇到这个问题。有什么建议、资源或代码可以帮助我吗?感谢您阅读我的帖子。
2个回答

15

你的代码在应用程序模板中的脚本块中调用了$("abbr.timeago").timeago();。这会在页面第一次加载时运行,并为那一刻存在的匹配元素启用timeago功能。任何后来动态添加的匹配节点 -- 比如你的AJAX部分 -- 都不会获得timeago功能。

一个选项是在添加动态内容后再次调用$("abbr.timeago").timeago()。然而,随着添加新功能的增多,很难跟踪并记得去做这件事,这就是为什么我使用livequery插件的原因。将livequery脚本包含在您的页面中,并用以下内容替换$("abbr.timeago").timeago();

$("abbr.timeago").livequery(function () { $(this).timeago(); });

现在可以在任何匹配的节点上启用时间轴动态添加的匹配节点。


它对我来说运行得很好,但唯一的问题是在使用动态内容时会有延迟,它会显示实时时间,然后在一两秒钟后才显示timeago :( 这在许多情况下都是不好的,因为它会显示丑陋的日期时间。 - Amr Elgarhy
你可以在CSS中设置: .timeago{ display: none }然后在livequery函数中只需编写$(this).show(); - Gorgi Rankovski
@AmrElgarhy 唯一的解决办法是默认显示一个漂亮的日期。 - rybo111

4

load()完成后,将调用ajaxComplete()。 我建议创建一个名为ready_or_not()的函数:

$(document).ready(function(){
  ready_or_not();
});

$(document).ajaxComplete(function(){
  ready_or_not();
});

function ready_or_not(){
  $(".timeago").timeago();
}

当文档加载完成或Ajax请求完成时,您可能只想运行特定代码。但无论哪种情况,都将其放在 ready_or_not() 函数内。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接