Ответ 1
Я бы изменил подход. Thymeleaf легко позволяет добавлять переменные модели в ваши шаблоны для использования в Javascript. В моих реализациях я обычно помещаю эти переменные где-то перед закрывающим тегом заголовка; чтобы они были на странице после загрузки JS. Я позволю шаблону решить, что именно загружать, конечно. Если вы показываете галерею, тогда визуализируйте ее так, как вы, и используйте атрибуты данных, чтобы определить галерею, относящуюся к некоторому JS-коду. Затем напишите себе приятный плагин jQuery для обработки вашей галереи.
Относительно базовый пример:
По умолчанию Layout Decorator: layout/default.html
<!doctype html>
<html xmlns:layout="http://www.thymeleaf.org" xmlns:th="http://www.thymeleaf.org">
<head>
<title>My Example App</title>
<object th:remove="tag" th:include="fragments/scripts :: header" />
</head>
<body>
<div layout:fragment="content"></div>
<div th:remove="tag" th:replace="fragments/scripts :: footer"></div>
<div th:remove="tag" layout:fragment="footer-scripts"></div>
</body>
</html>
То, что следует заметить здесь, - это включение общих сценариев нижнего колонтитула, а затем макет: определение фрагмента div. Этот макет div - это то, что мы собираемся использовать для включения нашего плагина jQuery, необходимого для галереи.
Файл с общими скриптами: fragments/scripts.html
<div th:fragment="header" xmlns:th="http://www.thymeleaf.org">
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
var MY_APP = {
contextPath: /*[[@{/}]]*/,
defaultTheme: /*[[${theme == null} ? null : ${theme}]]*/,
gallery: {
theme: /*[[${gallery == null} ? null : ${gallery.theme}]]*/,
images: /*[[${gallery == null} ? null : ${gallery.images}]]*/,
names: /*[[${gallery == null} ? null : ${gallery.names}]]*/
}
};
/*]]>*/
</script>
</div>
<div th:fragment="footer" xmlns:th="http://www.thymeleaf.org">
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/my_app.js"></script>
</div>
В файле сценариев есть два фрагмента, которые включены в декоратор. В фрагменте заголовка полезный контекстный путь включен для уровня JS, а также для defaultTheme только для ада. Затем объект галереи определяется и назначается из нашей модели. Фрагмент нижнего колонтитула загружает библиотеку jQuery и файл JS основного сайта снова для целей этого примера.
Страница с ленивой загруженной галереей: products.html
<html layout:decorator="layout/default" xmlns:layout="http://www.thymeleaf.org/" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Products Landing Page</title>
</head>
<body>
<div layout:fragment="content">
<h1>Products</h1>
<div data-gallery="lazyload"></div>
</div>
<div th:remove="tag" layout:fragment="footer-scripts">
<script type="text/javascript" src="/js/my_gallery.js"></script>
</div>
</body>
</html>
На нашей странице продуктов не так много. Используя декоратор по умолчанию, эта страница отменяет заголовок страницы в голове. Наш фрагмент контента включает заголовок в теге h1 и пустой div с атрибутом галереи данных. Этот атрибут - это то, что мы будем использовать в нашем плагине jQuery для инициализации галереи. Значение установлено на lazyload, поэтому наш плагин знает, что нам нужно найти идентификаторы изображений в некоторой переменной, заданной где-нибудь. Это может быть легко пустым, если единственное, что поддерживает наш плагин, - это lazyloaded gallery.
Таким образом, макет загружает некоторые скрипты по умолчанию и с умным размещением макета: фрагменты, вы позволяете определенным разделам сайта загружать библиотеки независимо от остальных.
Вот пример базового Spring контроллера для работы с нашим приложением: MyController.java
@Controller
public class MyController {
@RequestMapping("/products")
public String products(Model model) {
class Gallery {
public String theme;
public int[] images;
public String[] names;
public Gallery() {
this.theme = "basic";
this.images = new int[] {8,5,3,2};
this.names = new String[] {"Hey", "\"there's\"", "foo", "bar"};
}
}
model.addAttribute("gallery", new Gallery());
return "products";
}
}
Класс Gallery был брошен inline в методе продуктов, чтобы упростить наш пример здесь. Это может быть просто сервис или репозиторий какого-либо типа, который возвращает массив идентификаторов или все, что вам нужно.
Наш плагин jQuery, который мы создали, может выглядеть примерно так: my_gallery.js
(function($) {
var MyGallery = function(element) {
this.$el = $(element);
this.type = this.$el.data('gallery');
if (this.type == 'lazyload') {
this.initLazyLoadedGallery();
}
};
MyGallery.prototype.initLazyLoadedGallery = function() {
// do some gallery loading magic here
// check the variables we loaded in our header
if (MY_APP.gallery.images.length) {
// we have images... sweet! let fetch them and then do something cool.
PhotoGallery.load(MY_APP.gallery.images).loadTheme({
name: MY_APP.gallery.theme
});
// or if load() requires separate params
var imgs = MY_APP.gallery.images;
PhotoGallery.load(imgs[0],imgs[1],imgs[2],imgs[3]).loadTheme({
name: MY_APP.gallery.theme
});
}
};
// the plugin definition
$.fn.myGallery = function() {
return this.each(function() {
if (!$.data(this, 'myGallery')) {
$.data(this, 'myGallery', new MyGallery(this));
}
});
};
// initialize our gallery on all elements that have that data-gallery attribute
$('[data-gallery]').myGallery();
}(jQuery));
Окончательная рендеринг страницы продуктов будет выглядеть так:
<!doctype html>
<html>
<head>
<title>Products Landing Page</title>
<script type="text/javascript">
/*<![CDATA[*/
var MY_APP = {
contextPath: '/',
defaultTheme: null,
gallery: {
theme: 'basic',
images: [8,5,3,2],
names: ['Hey','\"there\'s\"','foo','bar']
}
};
/*]]>*/
</script>
</head>
<body>
<div>
<h1>Products</h1>
<div data-gallery="lazyload"></div>
</div>
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/my_app.js"></script>
<script type="text/javascript" src="/js/my_gallery.js"></script>
</body>
</html>
Как вы можете видеть, Thymeleaf делает довольно хорошую работу по переводу вашей модели на действительную JS и фактически добавляет кавычки там, где это необходимо, и избегает их. Когда страница заканчивается рендерингом, с плагином jQuery в конце файла все необходимое для инициализации галереи должно быть загружено и готово к работе.
Это не идеальный пример, но я думаю, что это довольно простой дизайн для веб-приложения.