Включить Javascript на определенные страницы в приложении Phoenix Framework

У меня есть немного Javascript, который я хочу включить только на определенные страницы в моем приложении Phoenix.

Сейчас у меня есть Javascript внутри тега script в myapp/web/templates/post/form.html.eex.

Я понимаю, что я могу переместить JavaScript на web/static/js/app.js... но я не хочу включать Javascript на каждую страницу (требуется только на двух конкретных страницах).

Какой лучший способ загрузить этот раздел Javascript на определенные страницы в моем приложении без дублирования кода и нарушить принцип DRY?

Ответ 1

1.

Поместите весь этот javascript из form.html.eex в свой собственный файл (возможно, что-то вроде 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.

Ответ 2

Вот один из способов добиться этого.

JavaScript, который у вас есть в теге script, вы перемещаете его в отдельный файл.

Вы делите свой "обычный" 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>

Ответ 3

Другой способ - использовать специфичные для страницы классы/элементы. Например, следующий код в app.js обеспечит выполнение кода только на странице lesson/show, поскольку только на этой странице есть элемент с идентификатором #lesson-container:

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

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

Ответ 4

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

Поместите свой код в новый .js файл. Включите тег script с источником в путь к файлу в соответствующих файлах html.

Ответ 5

Это основано на комментарии Газлера на вопрос и является несколько более общим ответом, чем , который был представлен cmititiuc. Вам не нужно строго оборачивать свой специфичный для страницы код 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 в шаблоне макета, вы добавили бы такой код в модуль просмотра поста:

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_existing и render заключается в том, что первый не вызовет ошибку, если ссылочный шаблон НЕ существует (и в этом случае ничего не будет выведено в HTML страницы).

Символ ~E предоставляет "HTML-безопасный синтаксис EEx внутри исходных файлов" и аналогичен (в большинстве случаев или, возможно, даже всегда) соответствующему коду из ответа cmititiuc:

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

Заключение

В общем случае, для любой страницы, для которой вы хотите импортировать определенные файлы JavaScript через элементы script на странице head (или в конце body), или связать CSS файлы, или сделать что-нибудь на странице выводя его часть, иначе обработанную макетом, вы использовали бы render_existing в шаблоне макета, как указано выше, а затем внедрили соответствующие предложения render в модулях просмотра для этих страниц.

И, кроме того, нет причин, по которым вы не могли бы использовать что-то похожее на оба приведенных выше примера, чтобы для любого модуля представления и его шаблонов вы могли оба:

  • Включите некоторые сценарии (или файлы CSS или иным образом управляйте выводом HTML в шаблоне макета) для всех шаблонов модуля представления (но не для всех шаблонов для всего приложения)
  • Включить несколько сценариев (или...) только для одного шаблона