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 文件,还是将其粘贴在标题查找的实例变量中?
我喜欢做的是在 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,您当然可以将其包含在页面内联中,但是如果您想对您的 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 做同样的事情,并以类似的方式将其分组以仅应用于站点的某些区域。
//= require_tree ./global
,我会收到 Sprockets::FileNotFound 错误,但如果我使用 Rails 3.2.12 使用 //= require_directory ./global
,则不会。
这些答案对我帮助很大!如果有人想要更多...
如果要预编译它们,则需要将 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.precompile
。 app/assets/javascripts/*.js
中的所有内容不是自动预编译的吗?
application.css
和 application.js
。其他必须包含在其他文件中,或使用 config.assets.precompile
列出。 Read more here
config.assets.precompile
和 config.assets.version
已移至 config/initializers/assets.rb
我更喜欢以下...
在您的 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' %>
...似乎对我有用。
如果您不想使用资产管道或 complex work arounds 来获取必要的特定于页面的 javascript(我表示同情),那么最简单、最可靠的方法与上面的答案相同,但代码更少,只是为了利用:
<%= javascript_include_tag "my_javascipt_file" %>
注意:与使用 content_for :head
的答案相比,这确实需要每个包含标签多一个 http 请求
javascript_include_tag
正是我想要的,干杯 AJP
//= require .
自动获取吗?
//= require .
会将该脚本带入您网站上的任何页面,因此您必须执行类似 Kenny Grant(使用 //= require_tree ./global
)或 bjg 建议的操作。
//= require_tree .
更改为 //= require_directory .
,然后在 assets\javascripts 中创建了一个子目录。请注意,您必须在 config\initializers\assets.rb 中包含新目录,以通过添加以下行来预编译您的 js:Rails.application.config.assets.precompile += %w( new_dir/js_file.js )
我的理解是,资产管道旨在通过将所有 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');
};
您使用导轨,所以我知道您喜欢宝石 :)
你不应该在资产管道之外加载你的 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 文件放入其中。然后它将在该特定操作上加载它。
好的,所以这可能是有史以来最糟糕的工作,但我创建了一个刚刚渲染出 .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"}
如果出于某种原因我们不想这样做,请告诉我。
添加 JS 的首选方式是在页脚中,因此您可以这样做:
显示.html.erb:
<% content_for :footer_js do %>
This content will show up in the footer section
<% end %>
布局/application.html.erb
<%= yield :footer_js %>
<%= javascript_include_tag "my_javascipt_file" %>
?