Вложенные шаблоны underscore.js
Возможно ли каким-либо образом взять элемент DOM из шаблона подчеркивания и использовать его в качестве другого шаблона?
Идея состоит в том, что моему приложению нужно отобразить документ, содержащий цикл с элементами и сводкой. Мне нужно иногда повторно отображать только сводку или несколько элементов, поэтому я не могу просто перерисовать весь документ.
Однако я бы хотел, чтобы пользователи приложений могли создавать собственные шаблоны для документа, и я думаю, что сохранить все в одном файле для документа упростит.
Я пытаюсь использовать что-то вроде этого:
<script type="text/template" id="document-template">
<div id="document">
<h1><%= name %></h1>
<ul class="items">
<% _.each(items, function(item) { %>
<li><%= item %></li>
<% }); %>
</ul>
<div id="summary">
<p>Total items: <%= totalitems %></p>
</div>
</div>
</script>
Теперь я могу легко сделать это var documentTemplate = _.template($('#document-template').html());
, чтобы превратить это в шаблон документа, но я хотел бы также превратить итоговую часть в шаблон и элемент списка в шаблон.
Могу ли я сделать что-то вроде этого:
var summaryTemplate = _.template($('#document-template #summary').html());
var itemTemplate = _.template($('#document-template .items li').html());
PS. Фактически я загружаю шаблон из внешнего файла с помощью jQuery $.get. Таким образом, я получу шаблон документа в одной большой строке. Оттуда я могу сделать только documentTemplate = _.template(loadedString);
.
Теперь, если бы я мог просто извлечь элемент #summary из строки, он должен работать. Но когда я пытаюсь преобразовать строку в элемент DOM (var domElement = $(loadedString)
)
(так что я мог бы сделать это: summaryTemplate = _.template($('#summary',domElement).html());
, он не будет работать, потому что подчеркивание больше не будет распознавать теги <% =% > .
Ответы
Ответ 1
Вы можете передать вложенный шаблон в качестве переменной в назначениях шаблона основному шаблону, например:
HTML:
<script type="text/template" id="sub_template">
<article>
<h1>id: <%= id %><h1>
</article>
</script>
<script type="text/template" id="main_template">
<% for (var i = 0; i < num; i++) { %>
<%= renderSub({id:i}) %>
<% } %>
</script>
JS:
var renderSub = _.template( $('#sub_template').remove().text() ),
renderMain = _.template( $('#main_template').remove().text() );
renderMain({num:5, renderSub:renderSub});
Ответ 2
/////// TEMPLATES //////
var mainTemplate = "<ul> \
<% _.each(items, function(item) { %> \
<%= listItem({item:item}) %> \
<% }); %> \
<ul>";
var subTemplate = '<li><%=item %></li>';
/////// MODEL (our data) //////
var model = {
items : [1,2,3,4,5]
}
/////// COMPILE //////
// add the subTemplate to the model data, to be passed to the mainTemplate
model.listItem = _.template(subTemplate);
// Render main template to the DOM
document.body.innerHTML = _.template(mainTemplate, model);
Ответ 3
Вместо того, чтобы загружать его сразу как один шаблон, а затем пытаться загрузить часть его позже, отделите их как несколько шаблонов.
У вас есть основной шаблон документа и итоговый шаблон. Начальная загрузка тянется в документе-шаблоне, а затем втягивается в итоговый шаблон и вставляет его в скомпилированный DOM из первого шаблона. Затем вы можете перезагрузить второй шаблон в любое время. См. Следующие шаги:
1) Загрузите начальный шаблон, показанный ниже:
<script type="text/template" id="document-template">
<div id="document">
<h1><%= name %></h1>
<ul class="items">
<% _.each(items, function(item) { %>
<li><%= item %></li>
<% }); %>
</ul>
</div>
</script>
2) После того, как это скомпилировано в DOM, загрузите второй шаблон с помощью подчеркивания, показанного ниже:
<script type="text/template" id="summary-template">
<div id="summary">
<p>Total items: <%= totalitems %></p>
</div>
</script>
3) Вызов $( "# document" ). append (summaryTemplate) или любая переменная содержит скомпилированный шаблон.
4) Повторяйте шаги 2 и 3 в любое время, когда вам нужно перезагрузить сводку, за исключением того, что сначала удалите существующие $( "# summary" ) перед добавлением снова
Вы можете использовать эту же стратегию для элементов, просто убедитесь, что вы используете правильные селектор/методы jQuery, чтобы переписывать существующие divs в правильном порядке, поскольку append будет работать только для добавления чего-либо к конец элемента.
Ответ 4
Я знаю, что я на 3 года опоздал на разговор, но ни один из этих ответов не применил вообще к ситуации, которая была у меня в моем последнем проекте. И так как изначально я думал об этом, я решил, что должен опубликовать его на случай, если кто-то еще захочет на самом деле вложить шаблоны underscore.js, как говорится в названии этого вопроса.
Мои требования были в основном:
1) Если в шаблоне есть динамические элементы, они должны иметь возможность повторно отображать их индивидуально - без необходимости повторного рендеринга всего шаблона с обновленными данными.
2) Динамические фрагменты не должны быть разбиты на свои собственные шаблоны на том же уровне, что и родительский шаблон; скорее, должна быть своего рода иерархия шаблонов - шаблон, объявляющий все необходимые подтемы для себя.
Понятие вложенных шаблонов в Underscore.js такое же, как в PHP (например). Следующий код является примером "эхо-ответа PHP":
<?php echo '<?php echo $var_unknown_until_runtime; ?>'; ?>
Хотя этот вложенный синтаксис может стать супер запутанным и запутанным, идея проста:
Эхо-код, который будет эхо-значения позже.
Это также применяется в шаблонах Underscore.js.
Пример
Код будет выглядеть так:
<script type="text/template" id="outer-tpl">
<%= value %>
<script type="text/template" id="inner-tpl">
<%= '<%= value %\>' %> <!-- NOTE how the inner '>' is escaped ('\>') -->
<%= "</script\>" %> <!-- NOTE same thing -->
</script>
Позвольте немного сломать это. Линия с первой NOTE
является нашей ключевой линией. Обычно, когда Underscore компилирует этот шаблон, вы ожидаете, что значение value
будет напечатано как в внешнем, так и в внутреннем шаблонах. Мы сделали несколько вещей, чтобы это не произошло:
1) Вставьте вложенное выражение подчеркивания в строку.
2) Интерполируйте эту строку (<%= "string here" %>
).
3) Побег закрытия >
во вложенном выражении подчеркивания (\>
). Это предотвращает совпадение регулярного выражения Underscore с тегом открытия с шага 2 (<%=
). Когда эта строка будет эхом, escape-символ будет удален, оставив %>
, готовый к интерпретации Underscore на следующем проходе.
Выполнение этой же задачи во втором NOTE
в нашем примере предотвращает завершение первого тега script
браузером. Вложенные теги script
технически не разрешены, поэтому браузер ищет первую последовательность символов: </script>
, а затем завершает выполнение script. Это не позволяет браузеру распознавать эту последовательность.
Для более подробного примера см. этот JSFiddle.
Отказ
Я не поддерживаю это как можно ближе к лучшему способу делать подобные вещи. Это, в конце концов, очень хаки. В то время как @John z отвечает, нарушает мое первое требование, которое не было для меня вариантом, другой вариант расщепления динамических элементов в шаблоне в их собственные шаблоны может быть легче справиться. Он менее организован.
Расположение всех этих вложенных тегов script
в DOM может быть сложно отслеживать (поскольку вложенные теги script
будут динамически вставляться в DOM, когда и где вы вставляете внешний шаблон). Риск дублирования является высоким и может раздражать его.
Трудность шаблонов вложенности резко возрастает для каждого уровня вложенности (чтобы вставить шаблон во вложенный шаблон, вам все равно придется скрывать все и т.д.). Пример скрипта включает пример.