使用Rails 3.1,您将“特定于页面的” JavaScript代码放在哪里?

| 据我了解,您所有的JavaScript都合并为1个文件。默认情况下,Rails在将“ 0”添加到“ 1”清单文件的底部时会执行此操作。 这听起来像是真正的救命稻草,但我有点担心页面特定的JavaScript代码。此代码是否在每个页面上执行?我想要的最后一件事是,当只在一页上需要所有对象时,将为每页实例化我的所有对象。 另外,代码是否也可能发生冲突? 还是在页面底部放置一个小的
script
标记,该标记只是调用执行该页面javascript代码的方法? 那么您不再需要require.js吗? 谢谢 编辑:我感谢所有的答案...,但我认为他们并没有真正解决问题。其中一些是关于样式的,似乎没有关系...而其他人只是提到了
javascript_include_tag
...,我知道它确实存在(显然...),但是看来Rails 3.1的发展方向是总结将您所有的JavaScript合并为1个文件,而不是在每个页面的底部加载单个JavaScript。 我能想到的最好的解决方案是用wrap5ѭ或
class
es在ѭ4wrap标签中包装某些功能。在JavaScript代码中,您只需检查页面上是否有
id
或ѭ6,,如果是,则运行与其关联的JavaScript代码。这样,如果动态元素不在页面上,则JavaScript代码将不会运行-即使Sprockets打包的巨大的“ 1”文件中也包含了JavaScript代码。 我上面的解决方案的好处是,如果搜索框包含在100页中的8页中,它将仅在这8页上运行。您也不必在网站的8个页面上包含相同的代码。实际上,您无需再在网站上的任何位置添加手动脚本标记。 我认为这是对我问题的实际答案。     
已邀请:
        Asset Pipeline文档建议如何执行特定于控制器的JS:   例如,如果生成一个“ 10”,则将在“ 11”创建一个新文件,而在“ 12”创建另一个文件。您应该将控制器特有的任何JavaScript或CSS放在其各自的资产文件中,因为这些文件仅可以用诸如
<%= javascript_include_tag params[:controller] %>
<%= stylesheet_link_tag params[:controller] %>
这样的行为这些控制器加载。 链接到:asset_pipeline     
        对于特定页面的js,您可以使用Garber-Irish解决方案。 因此,对于两个控制器(汽车和用户),您的Rails javascripts文件夹可能看起来像这样:
javascripts/
├── application.js
├── init.js
├── markup_based_js_execution
├── cars
│   ├── init .js
│   ├── index.js
│   └── ...
└── users
    └── ...
而且javascript看起来像这样:
// application.js

//= 
//= require init.js
//= require_tree cars
//= require_tree users
// init.js

SITENAME = new Object();
SITENAME.cars = new Object;
SITENAME.users = new Object;

SITENAME.common.init = function (){
  // Your js code for all pages here
}
// cars/init.js

SITENAME.cars.init = function (){
  // Your js code for the cars controller here
}
// cars/index.js

SITENAME.cars.index = function (){
  // Your js code for the index method of the cars controller
}
和markup_based_js_execution将包含UTIL对象的代码,并在DOM就绪的UTIL.init上执行。 并且不要忘记将其放置到布局文件中:
<body data-controller=\"<%= controller_name %>\" data-action=\"<%= action_name %>\">
我还认为,最好使用类而不是
data-*
属性,以获得更好的特定于页面的CSS。正如Jason Garber所提到的:特定于页面的CSS选择器可能真的很尴尬(当您使用
data-*
属性时) 我希望这能帮到您。     
        我们看到您已经回答了自己的问题,但这是另一个选择: 基本上,您假设
//= require_tree .
是必须的。不是。随时将其删除。老实说,在我当前的应用程序中,我第一次使用3.1.x,我制作了三个不同的顶级JS文件。我的
application.js
文件只有
//= require jquery
//= require jquery_ujs
//= require_directory .
//= require_directory ./api
//= require_directory ./admin
这样,我可以创建带有自己的顶级JS文件的子目录,这些子目录仅包含我需要的内容。 关键是: 您可以删除
require_tree
-Rails可让您更改其假设 名称
application.js
没什么特别的-
assets/javascript
子目录中的任何文件都可以包含带有
//=
的预处理程序指令 希望对您有所帮助,并为ClosureCowboy的答案添加一些细节。 苏加尔     
        另一个选择:创建页面或模型特定的文件,您可以在
assets/javascripts/
文件夹中创建目录。
assets/javascripts/global/
assets/javascripts/cupcakes
assets/javascripts/something_else_specific
可以将主main1ѭ清单文件配置为从ѭ33加载其文件。特定页面或页面组可以具有自己的清单,这些清单从它们自己的特定目录中加载文件。 Sprockets会自动将ѭ1加载的文件与特定于页面的文件合并,从而使该解决方案有效。 该技术也可用于ѭ35。     
我感谢所有答案...而且我认为他们并没有真正解决问题。其中一些是关于样式的,似乎没有关系...而其他人只是提到了
javascript_include_tag
...,我知道它确实存在(显然...),但是看来Rails 3.1的发展方向是总结将所有Javascript合并为1个文件,而不是在每个页面的底部加载单个Javascript。 我能想到的最好的解决方案是用wrap5ѭ或
class
es在ѭ4wrap标签中包装某些功能。在javascript代码中。然后,您只需检查页面上是否有
id
class
,如果是,则运行与之关联的javascript代码。这样,如果动态元素不在页面上,则javascript代码不会运行-即使Sprockets打包的巨大的“ 1”文件中也包含了该代码。 我上面的解决方案的好处是,如果搜索框包含在100页中的8页中,它将仅在这8页上运行。您也不必在网站的8个页面上包含相同的代码。实际上,您不必再在网站上的任何位置添加手动脚本标记-只需预先加载数据即可。 我认为这是对我问题的实际答案。     
我知道我来晚了一点,但是我想提出一个我最近一直在使用的解决方案。不过,我首先要提一下... Rails 3.1 / 3.2的方式(不,先生。我不喜欢它。) 请参阅:http://guides.rubyonrails.org/asset_pipeline.html#how-to-use-the-asset-pipeline 为了完整起见,我将以下内容包括在内,因为这不是可行的解决方案……尽管我不太在意。 “ Rails Way”是一个面向控制器的解决方案,而不是按此问题的原始作者要求的面向视图的解决方案。有特定于控制器的JS文件,它们以各自的控制器命名。所有这些文件都放在一个文件夹树中,该文件夹树默认情况下不包含在任何application.js require指令中。 为了包括特定于控制器的代码,将以下内容添加到视图中。
<%= javascript_include_tag params[:controller] %>
我讨厌这个解决方案,但是它在那里而且很快。大概,您可以改为将这些文件称为\“ people-index.js \”和\“ people-show.js \”,然后使用诸如“ѭ44”之类的格式来获得面向视图的解决方案。再次,快速修复,但它与我的配合不佳。 我的数据属性方式 叫我疯了,但是我希望在部署时将我的所有JS编译并缩小到application.js中。我不想记住到处都包含这些散乱的小文件。 我将所有JS加载到一个紧凑的,即将被浏览器缓存的文件中。如果需要在页面上触发我的application.js的某个片段,我让HTML告诉我,而不是Rails。 我没有将我的JS锁定到特定的元素ID或用标记类乱扔我的HTML,而是使用了一个称为“ 45”的自定义数据属性。
<input name=\"search\" data-jstag=\"auto-suggest hint\" />
在每个页面上,我都使用-在此处插入首选的JS库方法-在DOM完成加载后运行代码。该引导代码执行以下操作: 遍历标记为“ 47”的DOM中的所有元素 对于每个元素,在空间上分割属性值,创建一个标签字符串数组。 对于每个标签字符串,在哈希中执行该标签的查找。 如果找到匹配的键,请运行与其关联的功能,并将元素作为参数传递。 假设我在application.js的某处定义了以下内容:
function my_autosuggest_init(element) {
  /* Add events to watch input and make suggestions... */
}

function my_hint_init(element) {
  /* Add events to show a hint on change/blur when blank... */
  /* Yes, I know HTML 5 can do this natively with attributes. */
}

var JSTags = {
  \'auto-suggest\': my_autosuggest_init,
  \'hint\': my_hint_init
};
引导事件将对搜索输入应用
my_autosuggest_init
my_hint_init
函数,将其转变为一个输入,该输入在用户键入时显示建议列表,并在输入空白且不集中时提供某种输入提示。 除非某些元素用“ 51”标记,否则自动触发的代码永远不会触发。但是,它总是存在,缩小并最终在页面上需要的那些时间缓存在我的application.js中。 如果您需要将其他参数传递给标记的JS函数,则必须发挥一些创造力。添加数据参数属性,提出某种参数语法,甚至使用混合方法。 即使我有一些看似控制器特定的复杂工作流程,我也只会在我的lib文件夹中为其创建一个文件,将其打包到application.js中,并用\'new-thing-wizard \'进行标记。当我的引导程序点击该标签时,我的漂亮向导就会实例化并运行。它在需要时针对该控制器的视图运行,但未与该控制器耦合。实际上,如果我对向导进行了正确的编码,则也许可以在视图中提供所有配置数据,因此以后可以将向导重新用于需要它的任何其他控制器。 无论如何,这是我一段时间以来一直在实现页面特定的JS的方式,它对于简单的网站设计和更复杂/更丰富的应用程序都非常有用。希望我在这里介绍的两个解决方案之一(我的方式或Rails方式)对将来遇到此问题的任何人都有所帮助。     
        这个问题早在很早以前就已经得到了回答和接受,但是我根据其中一些答案以及我在Rails 3+方面的经验提出了自己的解决方案。 资产管道很不错。用它。 首先,在您的
application.js
文件中,删除
//= require_tree.
然后在
application_controller.rb
中创建一个辅助方法:
helper_method :javascript_include_view_js //Or something similar

def javascript_include_view_js
    if FileTest.exists? \"app/assets/javascripts/\"+params[:controller]+\"/\"+params[:action]+\".js.erb\"
        return \'<script src=\"/assets/\'+params[:controller]+\'/\'+params[:action]+\'.js.erb\" type=\"text/javascript\"></script>\'
    end
end
然后在您的
application.html.erb
布局文件中,在现有的javascript附件中添加带有help57ѭ助手前缀的新助手:
<head>
    <title>Your Application</title>
    <%= stylesheet_link_tag \"application\", :media => \"all\" %>
    <%= javascript_include_tag \"application\" %>
    <%= raw javascript_include_view_js %>
</head>
瞧,现在您可以使用在Rails中其他所有地方使用的相同文件结构轻松创建特定于视图的javascript。只需将文件保存在
app/assets/:namespace/:controller/action.js.erb
中即可! 希望对别人有帮助!     
您可以在布局文件(例如application.html.erb)中添加此行,以自动加载特定于控制器的javascript文件(生成控制器时创建的javascript文件):
<%= javascript_include_tag params[:controller] %>
您还可以添加一行以按操作自动加载脚本文件。
<%= javascript_include_tag params[:controller] + \"/\" + params[:action] %>
只需将页面脚本放入以控制器名称命名的子目录中即可。在这些文件中,您可以使用= require包含其他脚本。 创建一个仅在文件存在时就包括该文件的助手将是很好的,以避免浏览器出现404错误。     
        
<%= javascript_include_tag params[:controller] %>
    
        也许您会发现pluggable_js gem是合适的解决方案。     
        LoadJS gem是另一个选择:   LoadJS提供了一种在Rails应用程序中加载特定于页面的Javascript代码的方式,而不会失去Sprockets提供的魔力。您所有的Javascript代码都会在一个Javascript文件中继续最小化,但仅对某些页面执行。      https://github.com/guidomb/loadjs     
        菲利普的答案是相当不错的。这是使其工作的代码: 在application.html.erb中:
<body class=\"<%=params[:controller].parameterize%>\">
假设您的控制器称为“项目”,它将生成:
<body class=\"projects\">
然后在projects.js.coffee中:
jQuery ->
  if $(\'body.projects\').length > 0  
     $(\'h1\').click ->
       alert \'you clicked on an h1 in Projects\'
    
        仅当您告诉Rails(而不是Sprockets)合并JavaScript时,才会合并JavaScript。     
        这就是我解决样式问题的方法:(对不起,Haml)
%div{:id => \"#{params[:controller].parameterize} #{params[:view]}\"}
    = yield
这样,我将使用以下命令启动所有页面特定的.css.sass文件:
#post
  /* Controller specific code here */
  &#index
    /* View specific code here */
  &#new
  &#edit
  &#show
这样,您可以轻松避免任何冲突。 当涉及到.js.coffee文件时,您可以初始化元素,例如;
$(\'#post > #edit\') ->
  $(\'form > h1\').css(\'float\', \'right\')
希望这对一些人有所帮助。     
        您还可以将js分组到文件夹中,并根据页面继续使用资产管道有选择地加载JavaScript。     
        我同意您的回答,要检查该选择器是否存在,请使用:
if ($(selector).length) {
    // Put the function that does not need to be executed every page
}
(没有看到有人添加实际的解决方案)     
        我看不到真正能将所有内容组合在一起并为您提供答案的答案。因此,我将尝试将单调,sujal(la ClosureCowboy),Ryan的答案的第一部分,甚至是Gal关于Backbone.js的大胆声明……都以一种简短明了。而且,谁知道,我什至可以满足Marnen Laibow-Koser的要求。 范例编辑 资产/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require lodash.underscore.min
...
views / layouts / application.html.erb
  ...
  </footer>

  <!-- Javascripts ================================================== -->
  <!-- Placed at the end of the document so the pages load faster -->
  <%= javascript_include_tag \"application\" %>
  <%= yield :javascript %>

</body>
</html>
views / foo / index.html.erb
...
<% content_for :javascript do %>
  <%= javascript_include_tag params[:controller] %>
<% end %>
资产/javascripts/foo.js
//= require moment
//= require_tree ./foostuff
资产/javascripts/foostuff/foothis.js.coffee
alert \"Hello world!\"
简要描述;简介 从application.js中删除“ 0”,仅列出每个页面共享的JS。 上面在application.html.erb中显示的两行告诉页面在哪里包括application.js和您的页面特定的JS。 上面在index.html.erb中显示的三行告诉您的视图是查找特定于页面的JS,并将其包含在名为\“:javascript \”(或您想为其命名的名称)的指定屈服区域中。在此示例中,控制器为\“ foo \”,因此Rails将尝试在应用程序布局的:javascript yield区域中包括\“ foo.js \”。 在foo.js(或任何命名的控制器)中列出特定于页面的JS。列出公共库,树,目录等。 将自定义页面特定的JS放在某个地方,以便与其他自定义JS分开轻松地引用它。在此示例中,foo.js需要foostuff树,因此将您的自定义JS(例如foothis.js.coffee)放在此处。 这里没有硬性规定。随意移动事物,甚至在需要时甚至可以创建具有各种名称的多个产量区域。这只是表明可能迈出的第一步。 (鉴于我们使用Backbone.js的方式,我不会完全按照这种方式进行操作。我也可以选择将foo.js放到名为foo而不是foostuff的文件夹中,但尚未决定。) 笔记 您可以使用CSS和
<%= stylesheet_link_tag params[:controller] %>
做类似的事情,但这超出了问题的范围。 如果我错过了这里最出色的最佳实践,请给我发送便笺,我会考虑改编。 Rails对我来说还很陌生,说实话,到目前为止,对于默认情况下它给企业发展带来的混乱以及平均Rails程序产生的所有流量,我并没有留下深刻的印象。     
我有另一种解决方案,尽管原始方法对我来说很好,并且不需要任何花哨的选择性加载策略。放入标准文档就绪功能,但是然后测试当前的Windows位置,以查看它是否是您的JavaScript所针对的页面:
$(document).ready(function() {
   if(window.location.pathname.indexOf(\'/yourpage\') != -1) {
          // the javascript you want to execute
   }
}
这仍然允许将所有js通过rails 3.x装入一个小程序包中,但是不会产生太多开销或与不希望js的页面发生任何冲突。     
        ryguy的答案是一个很好的答案,即使它被否决了负面观点。 特别是如果您使用的是Backbone JS之类的东西,则每个页面都有自己的Backbone视图。然后erb文件只有一行内联javascript,可以启动正确的主干视图类。我认为它是单行的“胶水代码”,因此它的内联就可以了。优点是您可以保留\“ require_tree \”,从而使浏览器可以缓存所有javascript。 在show.html.erb中,您将看到类似以下内容的内容:
<% provide :javascript do %>
  <%= javascript_include_tag do %>
    (new app.views.ProjectsView({el: \'body\'})).render();
  <% end %>
<% end do %>
在您的布局文件中,您需要:
<%= yield :javascript %>
    
        将所有公共JS文件移动到\'app / assets / javascript / global \'等子文件夹,然后在application.js中,将“ 0”行修改为“ 81”。 现在,您可以随意将控制器特定的JS放在\'app / assets / javascript / \'根目录下,它们将不包含在已编译的JS中,仅当您通过controller82ѭ在控制器/视图上调用它们时才使用它们。     
        尽管您在这里有几个答案,但我认为您的编辑可能是最好的选择。从Gitlab获得的团队中使用的一种设计模式是Dispatcher模式。它的作用类似于您在说的,但是页面名称是通过rails在body标签中设置的。例如,在您的布局文件中,只需包含以下内容(在HAML中):
%body{\'data-page\' => \"#{controller}:#{action}\" }
然后在javascripts文件夹的
dispatcher.js.coffee
文件中只有一个闭包和switch语句,如下所示:
$ ->
  new Dispatcher()

class Dispatcher
  constructor: ->
    page = $(\'body\').attr(\'data-page\')
    switch page
      when \'products:index\'
        new Products() 
      when \'users:login\'
        new Login()
您需要在单个文件中进行的所有操作(例如,例如
products.js.coffee
login.js.coffee
)将它们封装在一个类中,然后对该类符号进行全球化,以便可以在分派器中对其进行访问:
class Products
  constructor: ->
    #do stuff
@Products = Products
Gitlab有几个这样的例子,如果您好奇的话,您可能想参考一下:)     
        Paloma项目提供了一种有趣的方法来管理页面特定的javascript代码。 他们的文档中的用法示例:
var UsersController = Paloma.controller(\'Users\');

// Executes when Rails User#new is executed.
UsersController.prototype.new = function(){
   alert(\'Hello Sexy User!\' );
};
    
        步骤1。删除require_tree。在您的application.js和application.css中。 第2步。在布局文件夹中编辑application.html.erb(默认为rails)。在以下标记中添加\“ params [:controller] \”。
<%= stylesheet_link_tag    \'application\', params[:controller], media: \'all\', \'data-turbolinks-track\' => true %>

<%= javascript_include_tag \'application\', params[:controller], \'data-turbolinks-track\' => true %>
第三步在config / initializers / assets.rb中添加文件
%w( controller_one controller_two controller_three ).each do |controller|
  Rails.application.config.assets.precompile += [\"#{controller}.js\", \"#{controller}.js.coffee\", \"#{controller}.css\", \"#{controller}.scss\"]
end
参考资料: http://theflyingdeveloper.com/controller-specific-assets-with-rails-4/     
        我还没有尝试过,但是看起来像是这样: 如果您有一个使用javascript的content_for(例如,其中包含真实的javascript),则链轮将不知道该内容,因此其工作方式与现在相同。 如果要从一大堆javascript中排除文件,则应进入config / sprockets.yml文件并相应地修改source_files。然后,您只需在需要的地方包括任何排除的文件。     
        我以前使用此方法进行过操作:http://theflyingdeveloper.com/controller-specific-assets-with-rails-4/。超级简单,依靠控制器来选择要加载的正确js。     
        我将一些答案合并为: 应用程序助手:
module ApplicationHelper
  def js_page_specific_include
    page_specific_js = params[:controller] + \'_\' + params[:action]
    if Rails.application.assets.find_asset(page_specific_js).nil?
      javascript_include_tag \'application\', \'data-turbolinks-track\' => true
    else
      javascript_include_tag \'application\', page_specific_js, \'data-turbolinks-track\' => true
    end
  end
end
layouts / application.html.haml:
 <!DOCTYPE html>
%html{lang: \'uk\'}
  %head   
    = stylesheet_link_tag \'application\', media: \'all\', \'data-turbolinks-track\' => true
   bla-bla-bla
    = js_page_specific_include   
   bla-bla-bla  
    
        首先:从application.js中删除ѭ94 第二:您所有的JS代码必须位于
/app/assets/javascritpt
,所有CSS代码必须位于
/app/assets/stylesheets
    
        在瑞安(Ryan)的带领下,这是我所做的- application.js.coffee
$ ->
    view_method_name = $(\"body\").data(\"view\") + \"_onload\"
    eval(\"#{view_method_name}()\") if eval(\"typeof #{view_method_name} == \'function\'\")
    view_action_method_name = $(\"body\").data(\"view\") + \"_\"+$(\"body\").data(\"action\")+\"_onload\"
    eval(\"#{view_action_method_name}()\") if eval(\"typeof #{view_action_method_name} == \'function\'\")
users.js.coffee(特定于控制器的咖啡脚本,例如controller:users,action:dashboard)
window.users_dashboard_onload = () ->
    alert(\"controller action called\")
window.users_onload = () ->
    alert(\"controller called\")
application.html.haml
%body{:data=>{:view=>controller.controller_name, :action=>controller.action_name}}
    
        这是执行此操作的方法,特别是如果您不必为特定页面执行大量库,而只需要多少运行几百行JS。 由于将Javascript代码嵌入HTML非常好,因此只需在app / views shared.js目录下创建,然后在my_cool_partial.html.erb内放置页面/页面特定的代码即可
<script type=\"text/javascript\"> 
<!--
  var your_code_goes_here = 0;
  function etc() {
     ...
  }
-->
</script>
因此,现在无论您想从哪里做,都可以:
  = render :partial => \'shared.js/my_cool_partial\'
就这样,k?     

要回复问题请先登录注册