it-roy-ru.com

Определение HTML-шаблона для добавления с использованием JQuery

У меня есть массив, который я перебираю. Каждый раз, когда условие выполняется, я хочу добавить копию кода HTML ниже к элементу контейнера с некоторыми значениями.

Где я могу поместить этот HTML для повторного использования умным способом?

<a href="#" class="list-group-item">
    <div class="image">
         <img src="" />
    </div>
    <p class="list-group-item-text"></p>
</a>

JQuery

$('.search').keyup(function() {
    $('.list-items').html(null);

    $.each(items, function(index) {
        // APPENDING CODE HERE
    });
});
103
Patrick Reck

Вы можете решить использовать шаблонизатор в вашем проекте, например:

Если вы не хотите включать другую библиотеку, John Resig предлагает решение jQuery , аналогичное приведенному ниже.


Браузеры и программы чтения с экрана игнорируют нераспознанные типы скриптов:

<script id="hidden-template" type="text/x-custom-template">
    <tr>
        <td>Foo</td>
        <td>Bar</td>
    <tr>
</script>

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

var template = $('#hidden-template').html();

$('button.addRow').click(function() {
    $('#targetTable').append(template);
});
137
Mathijs Flietstra

Старый вопрос, но так как вопрос требует "использования jQuery", я подумал, что предоставлю опцию, которая позволит вам сделать это без введения какой-либо зависимости от поставщика.

Несмотря на то, что существует множество шаблонизаторов, в последнее время многие из их функций перестали нравиться, с итерациями (<% for), условиями (<% if) и преобразованиями (<%= myString | uppercase %>), которые в лучшем случае рассматриваются как микроязык, а в худшем - анти-паттернами. Современные практики создания шаблонов поощряют простое отображение объекта в его DOM (или другом) представлении, например что мы видим со свойствами, сопоставленными с компонентами в ReactJS (особенно с компонентами без сохранения состояния).

Шаблоны внутри HTML

Одно свойство, на которое вы можете положиться для хранения HTML-кода вашего шаблона рядом с остальным HTML-кодом, - это использование неисполняемого <script>type, например, <script type="text/template">. Для вашего случая:

<script type="text/template" data-template="listitem">
    <a href="${url}" class="list-group-item">
        <table>
            <tr>
                <td><img src="${img}"></td>
                <td><p class="list-group-item-text">${title}</p></td>
            </tr>
        </table>
    </a>
</script>

При загрузке документа прочитайте ваш шаблон и токенизируйте его, используя простой String#split

var itemTpl = $('script[data-template="listitem"]').text().split(/\$\{(.+?)\}/g);

Обратите внимание, что с нашим токеном вы получаете его в чередующемся формате [text, property, text, property]. Это позволяет нам красиво отобразить его, используя Array#map, с функцией отображения:

function render(props) {
  return function(tok, i) { return (i % 2) ? props[tok] : tok; };
}

Где props может выглядеть как { url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }.

Собираем все вместе, если вы проанализировали и загрузили свое itemTpl, как указано выше, и у вас есть массив items в области видимости:

$('.search').keyup(function () {
  $('.list-items').append(items.map(function (item) {
    return itemTpl.map(render(item)).join('');
  }));
});

Этот подход также является всего лишь jQuery - вы должны быть в состоянии использовать тот же подход, используя javascript Vanilla с document.querySelector и .innerHTML.

jsfiddle

Шаблоны внутри JS

Вопрос, который нужно задать себе: действительно ли вы хотите/должны определять шаблоны как файлы HTML? Вы всегда можете компонентизировать + повторно использовать шаблон так же, как вы использовали бы большинство вещей, которые вы хотите повторить: с функцией.

В es7-land, используя деструктуризацию, строки шаблонов и функции-стрелки, вы можете написать довольно симпатичные функции компонентов, которые можно легко загрузить с помощью метода $.fn.html, описанного выше.

const Item = ({ url, img, title }) => `
  <a href="${url}" class="list-group-item">
    <div class="image">
      <img src="${img}" />
    </div>
    <p class="list-group-item-text">${title}</p>
  </a>
`;

Тогда вы можете легко отобразить его, даже сопоставленный с массивом, вот так:

$('.list-items').html([
  { url: '/foo', img: 'foo.png', title: 'Foo item' },
  { url: '/bar', img: 'bar.png', title: 'Bar item' },
].map(Item).join(''));

Да, и последнее замечание: не забывайте очищать свои свойства, передаваемые в шаблон, если они читаются из БД или кто-то может передать HTML (а затем запустить сценарии и т.д.) Со своей страницы.

129
Josh from Qaribou

Используйте шаблон HTML вместо!

Поскольку принятый ответ будет представлять метод перегрузки сценариев, я хотел бы предложить другой, который, на мой взгляд, намного чище и безопаснее из-за рисков XSS, связанных с перегрузкой сценариев.

Я сделал демо , чтобы показать вам, как использовать его в действии и как внедрить один шаблон в другой, отредактировать, а затем добавить в документ DOM.

пример HTML

<template id="mytemplate">
  <style>
     .image{
        width: 100%;
        height: auto;
     }
  </style>
  <a href="#" class="list-group-item">
    <div class="image">
      <img src="" />
    </div>
    <p class="list-group-item-text"></p>
  </a>
</template>

пример JS

// select
var t = document.querySelector('#mytemplate');

// set
t.content.querySelector('img').src = 'demo.png';
t.content.querySelector('p').textContent= 'demo text';

// add to document DOM
var clone = document.importNode(t.content, true); // where true means deep copy
document.body.appendChild(clone);

HTML & lttemplate>

  • + Его содержание эффективно инертно, пока не активировано. По сути, ваша разметка является скрытой DOM и не отображается.

  • + Любой контент в шаблоне не будет иметь побочных эффектов. Скрипты не запускаются, изображения не загружаются, звук не воспроизводится ... пока не будет использован шаблон.

  • + Контент считается отсутствующим в документе. Использование document.getElementById() или querySelector() на главной странице не вернет дочерние узлы шаблона.

  • + Шаблоны могут быть размещены в любом месте внутри <head>, <body> или <frameset> и могут содержать любой тип содержимого, допустимого в этих элементах. Обратите внимание, что "где угодно" означает, что <template> можно безопасно использовать в местах, запрещенных анализатором HTML.

Отступать

Поддержка браузера не должна быть проблемой, но если вы хотите охватить все возможности, вы можете легко проверить:

Чтобы включить функцию обнаружения <template>, создайте элемент DOM и убедитесь, что свойство .content существует:

function supportsTemplate() {
  return 'content' in document.createElement('template');
}

if (supportsTemplate()) {
  // Good to go!
} else {
  // Use old templating techniques or libraries.
}

Некоторые идеи о методе перегрузки скрипта

  • + Ничего не отображается - браузер не отображает этот блок, потому что тег <script> по умолчанию имеет display:none.
  • + Инертный - браузер не анализирует содержимое скрипта как JS, потому что его тип имеет значение, отличное от "text/javascript".
  • Проблемы безопасности - поощряет использование .innerHTML. Анализ строки времени выполнения предоставленных пользователем данных может легко привести к уязвимости XSS.

Полная статья: https://www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old

Полезная ссылка: https://developer.mozilla.org/en-US/docs/Web/API/Document/importNodehttp://caniuse.com/#feat=queryselector

28
DevWL

Добавить где-то в теле

<div class="hide">
<a href="#" class="list-group-item">
    <table>
        <tr>
            <td><img src=""></td>
            <td><p class="list-group-item-text"></p></td>
        </tr>
    </table>
</a>
</div>

затем создать CSS

.hide { display: none; }

и добавить в свой JS

$('#output').append( $('.hide').html() );
14
Mateusz Nowak

Другая альтернатива: Чистый

Я пользуюсь им, и это мне очень помогло. Пример показан на их сайте:

HTML

<div class="who">
</div>

JSON

{
  "who": "Hello Wrrrld"
}

Результат

<div class="who">
  Hello Wrrrld
</div>
3
alditis

Чтобы решить эту проблему, я признаю два решения:

  • Первый идет с AJAX, с которым вам нужно будет загрузить шаблон из другого файла и просто добавлять каждый раз, когда вы хотите, с помощью .clone() .

    $.get('url/to/template', function(data) {
        temp = data
        $('.search').keyup(function() {
            $('.list-items').html(null);
    
            $.each(items, function(index) {
                 $(this).append(temp.clone())
            });
    
        });
    });
    

    Примите во внимание, что событие должно быть добавлено после завершения ajax, чтобы убедиться, что данные доступны!

  • Вторым было бы добавить его в любом месте исходного HTML-кода, выделить его и спрятать в jQuery:

    temp = $('.list_group_item').hide()
    

    После добавления нового экземпляра шаблона вы можете

    $('.search').keyup(function() {
        $('.list-items').html(null);
    
        $.each(items, function(index) {
            $(this).append(temp.clone())
        });
    });
    
  • То же самое, что и предыдущий, но если вы не хотите, чтобы шаблон оставался там, а только в javascript, я думаю, вы можете использовать (не проверял!) .detach() вместо hide.

    temp = $('.list_group_item').detach()
    

    .detach() удаляет элементы из DOM, сохраняя данные и события живыми (.remove () - нет!).

2
Sebastian Neira