8

我正在构建一个 Rails 应用程序,它使用 Pusher 使用 Web 套接字将更新直接推送到客户端。在 JavaScript 中:

channel.bind('tweet-create', function(tweet){ //when a tweet is created, execute the following code:
  $('#timeline').append("<div class='tweet'><div class='tweeter'>"+tweet.username+"</div>"+tweet.status+"</div>");
});

这是代码和演示的令人讨厌的混合。所以自然的解决方案是使用 javascript 模板。也许生态或小胡子:

//store this somewhere convenient, perhaps in the view folder:
tweet_view = "<div class='tweet'><div class='tweeter'>{{tweet.username}}</div>{{tweet.status}}</div>"

channel.bind('tweet-create', function(tweet){ //when a tweet is created, execute the following code:
    $('#timeline').append(Mustache.to_html(tweet_view, tweet)); //much cleaner
});

这很好,除了我在重复自己。mustache 模板与我已经编写的用于从服务器呈现 HTML 的 ERB 模板 99% 相同。mustache 和 ERB 模板的预期输出/目的是 100% 相同的:将推文对象转换为推文 html。

消除这种重复的最佳方法是什么?

更新:尽管我回答了自己的问题,但我真的很想看看其他人的其他想法/解决方案——因此是赏金!

4

5 回答 5

5

imo 最简单的方法是在创建新推文时使用 AJAX 更新页面。这需要创建两个文件,第一个是标准的 html.erb 文件,第二个是 js.erb 文件。html.erb 将是标准表单,它可以在从数据库中提取所有推文后迭代并显示它们。js.erb 文件将是您在创建时附加新推文的简单 javascript,即:

$('#timeline').append("<div class='tweet'><div class='tweeter'><%= tweet.username %></div><%= tweet.status %></div>")

在新推文的表单中,您需要添加:

:remote => true

这将启用 AJAX。然后在创建操作中,您需要添加如下代码:

def create
...Processing logic...
  respond_to do |format|
    format.html { redirect_to tweets_path }
    format.js
  end
end

在这种情况下,如果您使用启用 AJAX 的表单发布推文,它将通过运行 create.js.erb 中的任何代码(即上面的 $('#timeline').append 代码)来响应调用. 否则它将重定向到您要发送的任何地方(在这种情况下,“索引”表示推文)。这是完成您想要做的事情的最干燥和最清晰的方式。

于 2011-03-01T18:36:29.223 回答
3

到目前为止,我找到的最佳解决方案是Isotope

它允许您使用可以由客户端和服务器呈现的 Javascript 编写模板。

于 2011-02-28T01:49:26.203 回答
3

我会用 Javascript 渲染所有推文。与其在服务器上呈现 HTML,不如在页面头部将初始数据设置为 JS。当页面加载时,使用 JS 渲染推文。

在你的脑海中:

%head
  :javascript
    window.existingTweets = [{'status' : 'my tweet', 'username' : 'glasner'}];

在一个 JS 文件中:

$.fn.timeline = function() {
  this.extend({
    template: "<div class='tweet'><div class='tweeter'>{{tweet.username}}</div>{{tweet.status}}</div>",
    push: function(hash){
      // have to refer to timeline with global variable
      var tweet = Mustache.to_html(timeline.template, hash)     
      timeline.append(tweet);
    }
  });  

  window.timeline = this;

  channel.bind('tweet-create', this.push);  

  // I use Underscore, but you can loop through however you want
  _.each(existingTweets,function(hash) {
    timeline.push(hash);
  });

  return this
};  


$(document).ready(function() {
  $('#timeline').timeline();
});
于 2011-03-02T15:22:57.680 回答
2

我还没有尝试过,但这只是我想到的一种可能的解决方案:

在您的视图中创建一个包含示例模板的隐藏 div(为简洁起见,我在这里使用 HAML):

#tweet-prototype{:style => "display:none"}
    = render :partial => Tweet.prototype

您的推文部分可以像现在一样呈现推文。

.tweet
    .tweeter
        = tweet.username
    .status
        = tweet.status

在创建推文原型时,您将所需的字段设置为 js-template 替换语法,您绝对可以将其干掉,但出于示例目的,我将其全部包含在此处。

# tweet.rb
def self.prototype
    Tweet.new{:username => "${tweet.username}", :status => "${tweet.status}"}
end

在客户端上,您会执行以下操作:

var template = new Template($('#tweet-prototype').html());
template.evaluate(.. your tweet json..);

最后一部分将取决于你如何做你的模板,但它会是这样的。

如前所述,我没有尝试过这种技术,它不会让你直接在模板中执行循环或条件格式等操作,但我相信你可以通过一些创造力来解决这个问题。

这与您希望使用 Isotope 进行的操作相距不远,并且在很多方面都较差,但这绝对是一个更简单的解决方案。就我个人而言,我喜欢 haml,并尝试在其中写尽可能多的标记,所以这对我个人来说是一个更好的解决方案。

我希望这有帮助!

于 2011-03-01T18:56:04.703 回答
1

为了能够使用 mustache 模板在 javascript 和 rails 之间共享模板,可以使用 smt_rails:https ://github.com/railsware/smt_rails (“Rails 3 的共享胡子模板”)以及 Poirot:https://github .com/olivernn/poirot

于 2012-06-21T13:15:27.847 回答