【问题标题】:Rails - how to include Javascript files only on certain pagesRails - 如何仅在某些页面上包含 Javascript 文件
【发布时间】:2016-09-18 12:08:45
【问题描述】:

我有一个所见即所得的编辑器,该编辑器已内置到网站中并进行了定制。有很多 Javascript 文件只需要在使用所见即所得编辑器的页面上加载;目前它们被加载在每个页面上(甚至在某些页面上破坏其他 Javascript)。

目前 Javascript 文件位于 assets/javascript/wysiwyg/ 中,并且不包含在 application.js 中的要求文件中,但由于资产管道(我认为)仍然包含在每个页面中。

我想知道我是否可以从其他页面中排除这些文件。是否可以将它们从资产管道移动到 public/ 目录并将它们(可能在咖啡脚本文件中?)导入到适当的视图中?

【问题讨论】:

  • @GrahamSlick 我不相信这是同一个问题。引用的页面是关于在您的应用程序中创建的特定于页面的 javascript 文件的问题(例如,person.js 用于 Person 模型)。如果我没看错,这个问题似乎是关于如何在每页的基础上手动加载 Javascript 文件。在我看来,这实际上是一个与引用问题不同的问题。不过,它可能仍然与另一个问题重复。

标签: javascript ruby-on-rails ruby ruby-on-rails-4 asset-pipeline


【解决方案1】:

您可以将任何想要手动加载的 Javascript 文件放在应用程序的 public/javascripts/lib 目录中,它们不会包含在资产管道中。然后,您可以在需要它们的页面上手动加载它们。

例如,在一个项目中,我使用了Chosen jQuery 插件,然后像这样加载它:

<script type="text/javascript" src="/javascripts/lib/chosen.jquery.min.js"></script>

Rails 将从public/ 获取公共文件,因此您只需从那里引用您的文件(删除public/ 位)。

这个项目相当大,有 88 个控制器、662 个动作,以及总共 38 个自定义 JavaScript 库,这些库在应用程序中偶尔使用,包括 Markdown 编辑器、图表库,甚至 jQuery UI。

为了管理蔓延并尽可能保持每个页面紧凑,我做了两件事:1)在我的控制器中,我设置了一个实例变量@page_libs,以列出要加载的库,以及 2) layout 在需要时使用@page_libs 中的值来包含特殊的Javascript。

控制器动作可能如下所示:

def edit
  @products = products.find(params[:id])
  @page_libs = [:ui, :textile]
end

app/views/layouts/application.html.erb 将其包含在正确的位置:

<%- if @page_libs&.include?(:ui) || @page_libs&.include?(:table) %>
    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
    <script type="text/javascript" src="/javascripts/lib/chosen.jquery.min.js"></script>
<% end -%>
<%- if @page_libs&.include?(:swiper) %>
    <script type="text/javascript" src="/javascripts/lib/idangerous.swiper.min.js"></script>
<% end -%>
<%- if @page_libs&.include?(:table) %>
    <script type="text/javascript" src="/javascripts/lib/jquery.handsontable.full.js"></script>
<% end -%>
<%- if @page_libs&.include?(:textile) %>
    <script type="text/javascript" src="/javascripts/lib/textile.js" charset="utf-8"></script>
<% end -%>

请注意,第一个包含用于 jQuery UI,我从 CDN 加载,而不是从我的应用程序的 public 加载。这种技术同样适用于外部库以及您托管的库。事实上,我的应用程序中的大多数页面只依赖于 2 个外部库(jQueryUnderscore.js),但可以选择从外部源加载多达 16 个其他 Javascript 库。限制页面上的外部库可以显着减少页面加载时间,直接提升应用程序的性能。

有时,Javascript 库也会包含 CSS 组件。或者,您甚至可以包含特定于页面的 CSS。外部样式表也可以采用相同的方法。这些是上述 Javascript 库的相应页面特定样式表“包含”:

<%- if @page_libs&.include?(:ui) %>
    <link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css">
    <link rel="stylesheet" type="text/css" href="/stylesheets/lib/chosen.min.css">
<% end -%>
<%- if @page_libs&.include?(:swiper) %>
    <link rel="stylesheet" type="text/css" href="/stylesheets/lib/idangerous.swiper.css">
<% end -%>

这样,我在项目中有一个点来管理库,而不管页面需要多少(或少数)。我最终可能会在 ApplicationController 中创建一系列自定义 before_action 处理程序,以定义页面需要包含哪些库。像这样的:

before_action: :include_library_ui,     only: [:new, :edit]
before_action: :include_library_swiper, only: [:show]

这将进一步清理控制器操作,并更容易识别依赖关系。然而,鉴于我的代码库的大小和剩余的紧迫任务,我还没有迈出这一步。也许它会激励你开始这样做。

【讨论】:

  • 谢谢,我会用这个方法。一个问题是有 50 个 js 文件,我不想单独链接它们。有没有办法链接它们所在的文件夹以及其中包含的所有 js 文件。
  • 当你说'链接'时,你的意思是在标题中吗?我相信你必须一次做一个。如果您从控制台列出目录,您应该能够创建一个编辑器脚本/宏,这将使该片刻工作。然后,您的挑战是决定您希望在哪些条件中包含哪些文件。
  • 是的,我就是这么想的,我会一次一个地链接它们。干杯
  • 清理layouts/application.html.erb 文件中的脚本标签的好方法是定义一个视图助手,将@page_libs 中的值映射到相应link / @ 的完整字符串值987654340@ 标签。然后,您的应用程序布局可以简单地调用&lt;% @page_libs.each do |l| %&gt; &lt;%= import_tag(l) %&gt; &lt;% end %&gt;
  • 嘿@MichaelGaskill - 我喜欢你的简单解决方案,谢谢!
【解决方案2】:

现在这已经过时了,我们处于使用 Rails 6 的 Webpacker 世界中,但是如果您想以老式 Sprockets 的方式使事情变得更简单,您可能会喜欢下面描述的方法。请注意,它确实是每个view - 其他答案对于更广泛的每个controller 东西有很好的方法。

让您的主布局声明一个“内容”部分。例如在application.htm.erb:

<!DOCTYPE html>
<html>
  <head>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    ...etc...

    <%= content_for :head %>

  </head>
  ...
</html>

这里,:head 只是一个标签,你可以给它任何你想要的名字。您也可以在布局中包含任意数量的此类声明。它们只是 Rails 让视图在外部布局的这些位中插入额外内容的方式。所以 - 您可以在各个视图中使用它来在布局的 &lt;head&gt; 部分中添加您的 JS 文件 &lt;script&gt; 标签。

例如,假设我通过将 zxcvbn.js 库的一个 JavaScript 文件复制到 vendor/assets/javascripts/zxcvbn.js 中手动“安装”了它。我有一个edit.html.erb 页面,这是必需的,所以在该文件的顶部,我添加:

<% content_for :head do %>
  <%= javascript_include_tag('zxcvbn', 'data-turbolinks-track': 'reload') %>
<% end %>

...删除 Turbolinks 属性,如果您不使用它。这意味着当 ERB 编译页面时,它会在布局的“内容为头”部分中替换该标签,因此脚本标签最终会在它的位置。这当然意味着页面加载时需要额外的 HTTP 获取,但仅限于使用它的视图中。在上面的例子中,JS 库非常大,通常只用于与用户更改密码相关的一两个地方;因此,尽管它几乎从未使用过,但与将其归为已编译的 application.js 并随处提供服务相比,这是一个巨大的胜利。

content_for 的东西非常聪明,因为它在引擎盖下非常简单。如果您的视图是由多个部分构建的,并且其中有多个进行声明,则它们不会相互覆盖。每个都被连接到正确的位置,所以最终结果几乎是你所期望的,没有任何令人讨厌的惊喜。

您还需要一个步骤来避免 Sprockets 出现异常,因为您尝试包含的资产不是预编译的。你需要告诉 Sprockets 它存在;由于某种原因,这不是自动确定的。在config/initializers/assets.rb 中,声明未包含在例如“带外”/未知文件中的文件。 application.js清单文件:

Rails.application.config.assets.precompile += %w( zxcvbn.js )

开箱即用的 Rails 生成的 assets.rb 有 cmets 解释这一点,并有一个注释掉的示例。

这一切都与资产管道正常协作,因此它与管道中的其他任何东西一样好(或坏,取决于您的经验!),在开发模式下具有调试版本,在生产中缩小内容(取决于您的管道配置)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 1970-01-01
    相关资源
    最近更新 更多