1

我有标准的 Rails 应用程序格式。

我有这些控制器:

class StaticPagesController < ApplicationController

  def help
  end

  def about
  end

end

我有文件app/assets/javascripts/static_page.js.coffee

我想要两件事:

  1. 当我运行 static_pages 的页面之一时才加载此 javascript

  2. 能够根据控制器内部的特定操作进行不同的 js 调用:

javascript 文件应如下所示:

//general javascript code
if (isThisHelpPage) {
   //Run some help page code
}

if (isThisAboutPage) {
   //Run some about page code
}

我认为第一个问题应该app/assets/javascripts/application.js通过添加一些规则以某种方式解决文件,例如:

//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require_tree .

//= (isItStaticController? render static_page.js.coffee)

但我想知道我该怎么做?

4

4 回答 4

1

不幸的是,您无法向应用程序 js 文件添加条件,因为它是在部署应用程序时预编译的。我可以在这里看到两种可能的方法对您有用:

1)像上面一样将所有的javascript放在一个文件中,然后在代码中设置页面,如下所示:

<script> page = "Help" </script> or <script> page = "About" </script>

你的脚本可能会变成:

if(page === "Help") .... else if(page === "About") ....

2) 另一种选择是为每个页面创建单独的 js 文件,然后通过 yield :head 块将它们合并到您的布局中。在您的帮助文件中,它看起来像这样:

<% content_for :head %>
  <%= javascript_include_tag 'help' %>
<% end %>

我个人喜欢在我的应用程序中使用第二种方法。

于 2012-08-28T22:03:30.483 回答
0

我将解释我如何处理这个问题。在我ApplicationController的身上,我有一个方法可以before_filter在每个请求上运行。

def prepare_common_variables
  controller_name = self.class.name.gsub(/Controller$/, '')
  if !controller_name.index('::').nil?
    namespace, controller_name = controller_name.split('::')
  end

  @default_body_classes = ["#{controller_name.underscore}_#{action_name} ".downcase.strip]
  @default_body_classes = ["#{namespace.underscore}_#{@default_body_classes.join}".strip] if !namespace.nil?
end

app/views/layouts/application.html.erb我有以下

<body class="<%= yield :body_classes %> <%= @default_body_classes.join(' ') %>">

对于您的StaticPagesController,当help操作运行时,这将生成以下<body>标记:

<body class="static_pages_help">

接下来,我有一个这样的方法app/assets/javascripts/application.js.erb

Array.prototype.diff = function(a) {
  return this.filter(function(i) {return !(a.indexOf(i) > -1);});
};

var DEEFOUR = (function (deefour) {
  deefour.Utility = (function (utility) {
    utility.hasBodyClass = function() {
      var args = Array.prototype.slice.call(arguments);
      if (args.length === 0 || $('body').get(0).attr('class') == "") return false;

      return args.diff($('body').get(0).attr('class').split(/\s/)).length == 0;
    };

    return utility;
  }(deefour.Utility || {}));

  return deefour;
}(DEEFOUR || {}));

最后,在我相当于你的情况下,app/assets/javascripts/static_page.js.coffee我会有这样的东西

$(function(){
  if (!DEEFOUR.Utility.hasBodyClass('static_pages_help')) return;

  // code for your help page
});

$(function(){
  if (!DEEFOUR.Utility.hasBodyClass('static_pages_about')) return;

  // code for your about page
});

这很好,因为在你看来

<% content_for :body_classes, :some_custom_class %>

或在特定动作中

@default_body_classes << "some_other_custom_class"

您可以有条件地添加特定的类以在您的 Javascript 中进行匹配。

// *both* 'static_pages_help' and 'some_other_class' are required
if (!DEEFOUR.Utility.hasBodyClass('static_pages_help') || !DEEFOUR.Utility.hasBodyClass('some_other_class')) return;

hasBodyClass(...)接受任意数量的参数;把它们列出来。这对于当表单提交失败时您希望运行相同的 Javascript 之new类的事情很有用。create

if (!DEEFOUR.Utility.hasBodyClass('some_controller_new', 'some_controller_create')) return;

应该注意的是,prepare_common_variables需要进行一些调整,因为它只允许单个命名空间 likeSomeNamespace::TheController而不是更多 like SomeNamespace::AnotherNamespace::TheController

于 2012-08-28T22:04:27.460 回答
0

这里的最佳实践是使用 content_for 辅助方法。有点像@Adam 所描述的,但你可能想<%= yield :script_files %>在布局文件的底部放一个,然后调用

<% content_for :script_files do %>
  <%= javascript_include_tag 'your_js_file' %>
<% end %>

从你想要的动作中。您可以通过遵循 Ryan Bates 在早期 Railscast 中提到的类似方法来做到这一点甚至更干净:

module ApplicationHelper
  def javascripts(paths)
    content_for :script_files do
      javascript_include_tag(paths.is_a?(Array) ? paths.join(',') : paths)
    end
  end
end

然后,您可以从您的操作视图中调用<% javascripts 'your_js_file' %>并包含该文件。

于 2012-08-28T22:22:54.347 回答
0

仅当我运行 static_pages 的页面之一时才加载此 javascript

首先,资产管道编译并创建静态资产文件offline,这意味着您不能在服务用户请求期间(在生产中)根据控制器名称动态创建捆绑包。

但是,您可以在相应的布局文件(StaticPages 控制器)中使用单独的<%= javascript_include_tag "static_page_manifest.js" %>语句而不是(包括application.js)来为特定视图定义某些 javascript。例如,您可以有一个app/assets/javascripts/static_page_manifest.js

//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require_tree .

//= static_page

或者,如果您想要动态 javascript 模块包含,您可以使用requirejs( requirejs-rails) 等。

能够根据控制器内部的特定操作进行不同的js调用

这可以通过检查id带有取决于控制器和动作名称的值的主体标签来实现!例如:

<body id="static_pages_<%= controller.action_name %>">
...

然后您可以在 javascript 包中检查此 id 值以执行某些代码片段。

于 2012-08-28T22:24:19.823 回答