ChatGPT解决这个技术问题 Extra ChatGPT

在 Rails 3 应用程序中添加页面特定 JavaScript 的最佳方法?

Rails 3 有一些非常酷的不显眼的 JavaScript。

但我想知道最好的方法是为特定页面包含额外的 JavaScript。

例如,我以前可能做过的地方:

<%= f.radio_button :rating, 'positive', :onclick => "$('some_div').show();" %>

我们现在可以用类似的东西让它不显眼

<%= f.radio_button :rating, 'positive' %>

# then in some other file
$('user_rating_positive').click(function() {
  $('some_div').show();
}

所以我想我的问题是在哪里/如何包含该 JavaScript?我不想填写 application.js 文件,因为此 JavaScript 仅适用于这一视图。我应该以某种方式为每个页面包含一个自定义 JavaScript 文件,还是将其粘贴在标题查找的实例变量中?

对于那些想要全面了解其工作原理和最佳方法的人,请阅读railsapps.github.io/rails-javascript-include-external.html。这是迄今为止我看到的关于这个主题的最好的文档。它不仅适用于 Rails,而且适用于任何从事 Web 开发的人。这就是为什么最好按照 Rails 的方式做事。我肯定会使用 Unholy Rails 来解决我未来的问题。哇。
@KateGregory 那个更新。

J
Justin Tanner

我喜欢做的是在 content_for :head 块中包含按视图 Javascript,然后在您的应用程序布局中将 yield 包含到该块中。例如

如果它很短,那么:

<% content_for :head do %>
  <script type="text/javascript">
    $(function() {
      $('user_rating_positve').click(function() {
        $('some_div').show();
      }
    });
  </script>
<% end %>

或者,如果更长,则:

<% content_for :head do %>
  <script type="text/javascript">
    <%= render :partial => "my_view_javascript"
  </script>
<% end %>

然后,在您的布局文件中

<head>
  ...
  <%= yield :head %>
</head>

为什么不使用 <%= javascript_include_tag "my_javascipt_file" %>
@AJP 我猜那它违背了资产管道的目的
@lulalala,但答案中的代码无论如何都不会这样做,而是以一种更混乱的方式?
@AJP 它更混乱,但它比你的答案少了一个 http 请求。
K
Kenny Grant

如果您只想在一个页面上包含 javascript,您当然可以将其包含在页面内联中,但是如果您想对您的 javascript 进行分组并利用资产管道、缩小的 js 等,则可以这样做并有额外的通过将您的 js 拆分为仅适用于站点的某些控制器/视图/部分的组来组合并仅加载到特定页面上的 js 资产。

将资产中的 js 移动到文件夹中,每个文件夹都有一个单独的清单文件,因此如果您有一个仅在后端使用的管理 js 库,您可以这样做:

assets javascripts admin ...js admin.js (manifest for admin group) application.js (manifest for app global group) global ...js

javascripts admin ...js admin.js (manifest for admin group) application.js (manifest for app global group) global ...js

管理员 ...js

...js

admin.js(管理员组的清单)

application.js(应用程序全局组的清单)

全球 ...js

...js

在现有的 application.js

//= require jquery
//= require jquery_ujs
//= require_tree ./global // requires all js files in global folder

在新的 admin.js 清单文件中

//= require_tree ./admin // requires all js files in admin folder

确保通过编辑 config/production.rb 加载这个新的 js 清单

config.assets.precompile += %w( admin.js )

然后调整你的页面布局,这样你就可以在页面头部包含一些额外的js:

<%= content_for :header %>   

然后在您想要包含此特定 js 组(以及普通应用程序组)和/或任何特定于页面的 js、css 等的视图中:

<% content_for :header do %>
  <%= javascript_include_tag 'admin' %>  
<% end %>

您当然可以对 css 做同样的事情,并以类似的方式将其分组以仅应用于站点的某些区域。


如果您将所有清单保存在同一个位置,您可以告诉 rails 预编译该文件夹中的所有内容。这样您只需要编辑一次 production.rb 并且不跟踪您添加的内容。
不知道你能做到这一点 - 所以你可以有一个包含你的清单以及各个 js 组的“清单”文件夹?我可以试试这个。我确实希望他们在默认情况下有一个稍微健全的设置,因为他们似乎认为你只会将所有 js 集成到一个随处导入的大文件中。
奇怪的是,如果我使用 //= require_tree ./global,我会收到 Sprockets::FileNotFound 错误,但如果我使用 Rails 3.2.12 使用 //= require_directory ./global,则不会。
看起来您最终会得到许多脚本标签。我认为资产管道的目标是只有一个脚本标签?我只会编写 javascript,以便它们是特定于页面的。
我想我明白。不过,避免额外的脚本标签对页面加载时间非常重要。
M
Maximus S

这些答案对我帮助很大!如果有人想要更多...

如果要预编译它们,则需要将 javascripts 放入清单中。但是,如果您需要 application.js.coffee 中的每个 javascript 文件,那么每次导航到不同的页面时都会加载所有 javacsripts,并且执行特定于页面的 javascripts 的目的将被破坏。

因此,您需要创建自己的清单文件(例如 speciifc.js),它需要所有特定于页面的 javascript 文件。另外,从 application.js 修改 require_tree

应用程序/资产/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require_tree ./global

应用程序/资产/javascripts/specific.js

//= require_tree ./specific

然后在您的 environments/production.rb 中使用配置选项将此清单添加到预编译列表中,

config.assets.precompile += %w( specific.js )

完毕!所有应始终加载的共享 javascript 将放置在 app/assets/javascripts/global 文件夹中,而特定于页面的 javascript 将放置在 app/assets/javascripts/specific 中。您可以简单地从视图中调用特定于页面的 javascript,例如

<%= javascript_include_tag "specific/whatever.js" %> //.js 是可选的。

这已经足够了,但我也想使用 javascript_include_tag params[:controller]。当您创建控制器时,会在 app/assets/javascripts 中生成一个关联的咖啡脚本文件,就像其他人提到的那样。有真正的 controller-specific javascripts,只有当用户到达特定的控制器视图时才会加载。

所以我创建了另一个清单 controller-specific.js

应用程序/资产/javascripts/controller-specific.js

//= require_directory .

这将包括与控制器关联的所有自动生成的咖啡脚本。此外,您需要将其添加到预编译列表中。

config.assets.precompile += %w( specific.js controller-specific.js )


非常感谢详细的回答。我应该把这行 javascript_include_tag params[:controller] 放在哪里。目前我的 application.html.erb 有这一行 javascript_include_tag 'application' 。我应该用另一行替换它吗?
另外,我应该将此行 <%= javascript_include_tag "specific/whatever.js" %> 放在 content_for :header 块中吗?
我很奇怪你需要弄乱 config.assets.precompileapp/assets/javascripts/*.js 中的所有内容不是自动预编译的吗?
@AlexChaffee 只有自动可用的文件是 application.cssapplication.js。其他必须包含在其他文件中,或使用 config.assets.precompile 列出。 Read more here
清单声明已被移动。我正在运行rails 4.2.0。并在 production.rb 文件中找到此注释:# config.assets.precompileconfig.assets.version 已移至 config/initializers/assets.rb
c
cailinanne

我更喜欢以下...

在您的 application_helper.rb 文件中

def include_javascript (file)
    s = " <script type=\"text/javascript\">" + render(:file => file) + "</script>"
    content_for(:head, raw(s))
end

然后在您的特定视图中(本示例中为 app/views/books/index.html.erb)

<% include_javascript 'books/index.js' %>

...似乎对我有用。


C
Community

如果您不想使用资产管道或 complex work arounds 来获取必要的特定于页面的 javascript(我表示同情),那么最简单、最可靠的方法与上面的答案相同,但代码更少,只是为了利用:

<%= javascript_include_tag "my_javascipt_file" %>

注意:与使用 content_for :head 的答案相比,这确实需要每个包含标签多一个 http 请求


javascript_include_tag 正是我想要的,干杯 AJP
你把“my_javascipt_file”放在哪里?在资产/javascripts 中?但如果是这样,那不是在 application.js 中使用 //= require . 自动获取吗?
@Linus 是的,//= require . 会将该脚本带入您网站上的任何页面,因此您必须执行类似 Kenny Grant(使用 //= require_tree ./global )或 bjg 建议的操作。
这对我来说是迄今为止最简单的方法,我将 application.js 中的 //= require_tree . 更改为 //= require_directory .,然后在 assets\javascripts 中创建了一个子目录。请注意,您必须在 config\initializers\assets.rb 中包含新目录,以通过添加以下行来预编译您的 js:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
p
peresleguine

看看 pluggable_js 宝石。您可能会发现此解决方案更易于使用。


Z
Ziggy

我的理解是,资产管道旨在通过将所有 js 混合到一个(缩小的)文件中来减少页面加载时间。虽然这表面上看起来令人反感,但它实际上是 C 和 Ruby 等流行语言中已经存在的特性。诸如“包含”标签之类的东西旨在防止文件的多次包含,并帮助程序员组织他们的代码。当您使用 C 编写和编译程序时,所有这些代码都存在于正在运行的程序的每个部分中,但是方法仅在使用该代码时才加载到内存中。从某种意义上说,编译后的程序不包含任何东西来保证代码是很好的模块化。我们通过以这种方式编写程序来使代码模块化,并且操作系统仅将给定位置所需的对象和方法加载到内存中。甚至有“特定方法的包含”之类的东西吗?如果您的 Rails 应用程序是安静的,那么这基本上就是您所要求的。

如果您编写 javascript 以增强页面上 HTML 元素的行为,那么这些功能在设计上是“特定于页面的”。如果您编写的某些复杂代码无论其上下文如何都将执行,则可以考虑将该代码绑定到一个 html 元素(您可以使用 body 标记,如 Garber-Irish method 中所述)。如果一个函数有条件地执行,性能可能会小于所有那些额外的脚本标签。

我正在考虑使用 paloma gem,如 rails apps project 中所述。然后,您可以通过在 paloma 回调中包含特定于页面的函数来使您的 javascript 页面特定于:

Paloma.callbacks['users']['new'] = function(params){
    // This will only run after executing users/new action
    alert('Hello New Sexy User');
}; 

您使用导轨,所以我知道您喜欢宝石 :)


E
Erick Maynard

你不应该在资产管道之外加载你的 JS 或 CSS 文件,因为你失去了让 Rails 如此出色的重要特性。而且您不需要其他宝石。我相信使用尽可能少的宝石,这里不需要使用宝石。

您想要的是“特定于控制器的 Javascript”(“特定于操作的 Javascript 包含在底部)。这允许您为特定的控制器加载特定的 JavaScript 文件。尝试将您的 Javascript 连接到视图是一种.. . 倒退并且不遵循 MVC 设计模式。您希望将其与控制器或控制器内的操作相关联。

不幸的是,无论出于何种原因,Rails 开发人员决定默认情况下,每个页面都会加载位于资产目录中的每个 JS 文件。为什么他们决定这样做而不是默认启用“控制器特定的 Javascript”,我永远不会知道。这是通过 application.js 文件完成的,该文件默认包含以下代码行:

//= require_tree .

这称为指令。这是 sprockets 用来加载 assets/javascripts 目录中的每个 JS 文件的方法。默认情况下,sprockets 会自动加载 application.js 和 application.css,并且 require_tree 指令会加载各自目录中的每个 JS 和 Coffee 文件。

注意:当你使用脚手架时(如果你不是脚手架,现在是开始的好时机),Rails 会自动为你生成一个咖啡文件,用于该脚手架的控制器。如果你希望它生成一个标准的 JS 文件而不是一个咖啡文件,那么删除你的 Gemfile 中默认启用的咖啡 gem,你的脚手架将创建 JS 文件。

好的,所以启用“控制器特定 Javascript”的第一步是从 application.js 文件中删除 require_tree 代码,或者如果您仍然需要全局 JS 文件,则将其更改为 assets/javascripts 目录中的文件夹。 IE:

//= require_tree ./global

第 2 步:进入 config/initializers/assets.rb 文件,并添加以下内容:

%w( controllerone controllertwo controllerthree ).each do |controller|
  Rails.application.config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
end

插入所需的控制器名称。

第 3 步:将 application.html.erb 文件中的 javascript_include_tag 替换为此(注意 params[:controller] 部分:

<%= javascript_include_tag 'application', params[:controller], 'data-turbolinks-track': 'reload' %>

重新启动您的服务器和中提琴!使用脚手架生成的 JS 文件现在只会在调用该控制器时加载。

需要在控制器中的特定 ACTION 上加载特定的 JS 文件,IE /articles/new ?改为这样做:

应用程序.html.erb:

<%= javascript_include_tag "#{controller_name}/#{action_name}" if AppName::Application.assets.find_asset("#{controller_name}/#{action_name}") %>

配置/初始化程序/assets.rb:

config.assets.precompile += %w(*/*)

然后在 assets/javascripts 文件夹中添加一个与控制器同名的新文件夹,并将与您的操作同名的 js 文件放入其中。然后它将在该特定操作上加载它。


B
Bill

好的,所以这可能是有史以来最糟糕的工作,但我创建了一个刚刚渲染出 .js 文件的控制器方法

控制器

def get_script
   render :file => 'app/assessts/javascripts/' + params[:name] + '.js'
end
def get_page
   @script = '/' + params[:script_name] + '.js?body=1'
   render page
end

看法

%script{:src => @script, :type => "text/javascript"}

如果出于某种原因我们不想这样做,请告诉我。


S
Syed

添加 JS 的首选方式是在页脚中,因此您可以这样做:

显示.html.erb:

<% content_for :footer_js do %>
   This content will show up in the footer section
<% end %>

布局/application.html.erb

<%= yield :footer_js %>