在 Phoenix 框架应用程序的某些页面上包含 Javascript

Include Javascript on Certain Pages in Phoenix Framework Application

我有一些 Javascript 只想包含在我的 Phoenix 应用程序的某些页面上。

现在我在 myapp/web/templates/post/form.html.eex.

的脚本标签中得到了 Javascript

我知道我可以将 JavaScript 移动到 web/static/js/app.js ...但我不想在每个页面上都包含 Javascript(仅在特定的 2 个页面上需要页)。

在我的应用程序的某些页面上加载 Javascript 的这一部分而不重复代码和违反 DRY 原则的最佳方法是什么?

<script src="myscripts.js"></script>

将您的代码放入新的 .js 文件中。在相关 html 文件中的文件路径中包含带有源的脚本标记。

这是实现此目的的一种方法。

你在脚本标签中的JavaScript,你把它移到一个单独的文件中。

您将 "regular" javascript(将包含在每个页面中)和此自定义 javascript(将包含在某些特定页面中)划分到单独的目录中。例如app/common/standard.js 和 app/custom/unique.js

您将brunch-config.js修改为如下:

module.exports = {
 files: {
    javascripts: {
      joinTo: {
        'custom.js': /^app[\\/]common[\\/][\S*?]\.js/,
        'app.js': /^app[\\/]common[\\/][\S*?]\.js/
        }
    }
}

然后在所有页面中包含 app.js,

<script src="<%= static_path(@conn, "/js/app.js") %>"></script>

但 custom.js 仅在需要它的页面(或布局)模板中。

<script src="<%= static_path(@conn, "/js/custom.js") %>"></script>

1.

form.html.eex 中的所有 javascript 放入其自己的文件中(可能类似于 js/posts.js).

在底部添加:

export var Post = { run: function() {
  // put initializer stuff here
  // for example:
  // $(document).on('click', '.remove-post', my_remove_post_function)
}}

2.

在您的 app.html 中,在 <script src="#{static_path(@conn, "/js/app.js")}"></script> 下添加:

<%= render_existing @view_module, "scripts.html", assigns %>

3.

然后,在你看来(大概是views/post_view.ex),添加这样的方法:

def render("scripts.html", _assigns) do
  ~s{<script>require("web/static/js/posts").Post.run()</script>}
  |> raw
end

结论

现在 javascript 文件 post.js 将仅在使用 post 视图时加载。

另一种方法是使用特定页面 classes/elements。例如,app.js 中的以下代码将确保代码仅在 lesson/show 页面上执行,因为只有该页面具有 ID 为 #lesson-container:

的元素
import { startLesson } from './lesson/show.ts';

if (document.querySelector('#lesson-container')) {
  startLesson();
}

这是基于 and is a slightly more general answer than 。您不需要像在该答案中那样严格地包装特定于页面的 JavaScript 代码,也不需要在特定于页面的 script 元素中导入特定于页面的文件。

布局模板

在您的布局中使用 Phoenix.View.render_existing/3,如下所示:

<head>
  <%= render_existing @view_module, "scripts.html", assigns %>
</head>

...或者这个:

<head>
  <%= render_existing @view_module, "scripts." <> @view_template, assigns %>
</head>

对于第一个示例,这将呈现一个 "scripts.html" 模板(如果相关视图模块存在)。

对于第二个示例,"scripts." <> @view_template 模板,例如scripts.form.html,存在则渲染

如果视图模块的 'scripts' 模板不存在,则页面中不会输出任何内容 HTML。

查看模块

对于在布局模板中使用 render_existing/3 的第一个示例,您需要将如下代码添加到 post 视图模块:

def render("scripts.html", _assigns) do
  ~E(<script src="file.js"></script>)
end

...然后您将添加如下代码:

def render("scripts.show.html", _assigns) do
  ~E(<script src="show-file.js"></script>)
end

def render("scripts.index.html", _assigns) do
  ~E(<script src="index-file.js"></script>)
end

详情

render_existingrender 的区别在于,如果引用的模板不存在,前者不会引发错误(并且页面中不会输出任何内容 HTML在那种情况下也是如此)。

The ~E sigil provides "HTML safe EEx syntax inside source files" and is similar to (in most cases, or maybe even always) the corresponding code from :

~s{<script>require("web/static/js/posts").Post.run()</script>}
|> raw

结论

一般来说,对于任何要通过页面 head 中的 script 元素(或 body), 或 link CSS 文件,或对其中由布局处理的部分页面输出执行任何操作,您将在布局模板中使用 render_existing 如上所述,并且然后在这些页面的视图模块中实施适当的 render 子句。

此外,您没有理由不使用上面两个示例中的 both 这样的东西,这样对于任何视图模块及其模板,您都可以:

  • 所有视图模块包含一些脚本(或CSS文件或以其他方式操纵布局模板中的HTML输出)模板(但不是整个应用程序的所有模板)
  • 仅为一个模板包含一些脚本(或...)