在 Rails 5.2 应用程序中,我应该将特定页面的 javascript 放在哪里?

Where do I place my javascript for a specific page in a Rails 5.2 application?

目前我的两个表单视图中有以下 script

<script>

$('#standard_calendar').calendar();
$('#time_calendar').calendar({type: 'time'});

</script>

我可以把它们放在哪里,这样它们就可以访问但不会与我的 HTML 混在一起?

你有两个选择(我假设你已经安装了 webpacker):

  1. 您可以在 app/javascript/components 文件夹中创建一个新的 js 文件。然后将此文件导入application.jsapplication.jsapplication.html.erb 中所有 javascript 到 <%= javascript_pack_tag 'application' %> 的入口点。那么您的脚本将在所有页面上被调用。
  2. 或者但这仅在您不使用 turbolinks 时有效,您可以在 app/javascript/packs 中为您的脚本创建一个新文件,然后在相应的视图中,您使用 <%= javascript_pack_tag 'file_name' %>.所以如果你调用你的文件 calendar.js 它将是 <%= javascript_pack_tag 'calendar' %> 然后你的脚本将只在这个视图页面上被调用。

如果您遵循第二个选项,并且如果您在底部的 application.html.erb 中有主要 <%= javascript_pack_tag 'application' %>,还有一个提示:

这意味着,您在呈现主 application.js 之前调用您的日历脚本,这可能会导致错误。避免这种情况的一种方法是在 application.html.erb 中创建第二个 yield 并像这样使用它:

application.html.erb
<body>
    <%= yield %>
    <%= render "shared/footer" %>
    <%= javascript_include_tag 'application' %>
    <%= javascript_pack_tag 'application' %>

    <%= yield(:after_js) %>
  </body>

然后在您看来您可以执行以下操作:

views/somthing/index.html.erb
...
<%= content_for :after_js do %>
  <%= javascript_pack_tag 'calendar' %>
<% end %>

此流程如下:application.html.erb 正在渲染正文并包含视图文件中的 html 代码。然后它呈现一个页脚(例如)。然后它调用 application.js 可能会导入一些通用的 JS 代码和包。然后第二个 yield 再次调用视图中的块,该块具有日历的特定脚本。

您的脚本最好预先打包并连接到一个文件中,以避免多个 HTTP 请求。无需依赖在特定页面上加载一组特定的 JavaScript,您只需将数据属性或 class 添加到 body 元素并使用它来切换您的行为。这不仅对性能更好,而且可以避免与 turbolinks 相关的问题以及跨页面访问的持久浏览器会话。

我前一段时间写了 a gem for this,但已经有一段时间没有维护了,但我基本上通过以下方式解决了它:

<body data-action="<%= action_name %>" data-controller="<%= controller_name %>">

$(document).on('turbolinks:load', function(){
  let data = $('body').data();
  // pagescript: is just the namespace for the events to avoid potential name collisions 
  // Use whatever you want instead
  $(document).trigger('pagescript:' + data.controller + '#' + data.action, data)
             .trigger('pagescript:' + data.controller + '#*', data)
             .trigger('pagescript:' + '*#' + data.action , data);
});

这会在每次页面更改时触发一组自定义事件。您可以添加事件侦听器以侦听特定页面或操作:

// A specific controller_name and action
$(document).on('pagescript:controller_name#action_name', (e) => { });
// Any action belonging to a specific controller
$(document).on('pagescript:controller_name#*', (e) => { });
// Any action matching action_name
$(document).on('pagescript:*#action_name', (e) => { });

例如:

$(document).on('pagescript:users#new', (e) => { 
  alert("Welcome new user!");
});

不过这个问题也可以通过更好的代码设计来解决。考虑可用于增强任何页面行为的模块,而不是编写代码来增强特定页面上的特定装饰。