Визначення HTML-шаблону для додавання за допомогою JQuery


125

У мене є масив, через який я переглядаю. Щоразу, коли умова виконується, я хочу додати копію 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
    });
});

2
Якщо ви шукаєте розумний спосіб, введіть всю свою інформацію в один DIV і оформіть її. Не створюйте численні таблиці з лише двома клітинками, не загортайте їх у якіри.
Сергій Снігірьов

3
ОП, очевидно, зацікавлені в правильній практиці кодування (кудо!), Тому я хотів допомогти. Якби я хотів зробити свій внесок у актуальну проблему, я опублікував би відповідь. Я впевнений, що хтось погоджується, що використання повнокольорової двоклітинної таблиці для позиціонування зображення та деякого тексту ледве виправдано за винятком якихось дійсно екзотичних вимог (IE4?)
Сергій Снєгірьов,

1
@BrianG. Опублікування коментаря насправді не означає, що ви їдете по дотичній, хоча. Хоча я погоджуюся, що коментарі є відповідним місцем для тих (поки вони все ще актуальні), вони також підходять для підказки людей, які ще не встигають розгорнути їх на відповідь. Корисно для ОП, щоб було зрозуміло, що ви робите.
мільмозу

Ніхто не відповів на ваше запитання, Патріку?
Себастьян Нейра

Відповіді:


164

Ви можете вирішити використовувати двигун-шаблон у своєму проекті, наприклад:

Якщо ви не хочете включати іншу бібліотеку, 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);
});

@MaksimLuzik має рацію. Вуса (зверніть увагу на написання торговельної марки) мають меншу вагу і будуть включені до коду ОП, але руль має більше можливостей для обробки масивів, і може в кінцевому підсумку забезпечити більш достатнє рішення. Ось приємна стаття для порівняння: blog.cubettech.com/…
Майкл

13
Приклад того, як редагувати шаблон тут: jsfiddle.net/meehanman/7vw8bc84
Дін Механ

175

Старе запитання, але оскільки в цьому питанні задається "використання jQuery", я подумав, що я б запропонував варіант, який дозволяє це робити, не вводячи жодної залежності від постачальника.

Незважаючи на те, що там є багато двигунів-шаблонів, багато їхніх функцій останнім часом припали до зневаги: ​​ітерація ( <% for), conditionals ( <% 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 з 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 (а потім запустити сценарії тощо) зі своєї сторінки.


1
Хороший шаблон двигуна.
Артур Кастро

41
Ваші шаблони всередині розділу JS - це бомба
BigRon

2
Чи можете ви додати демо / скрипку для підходу "Шаблони всередині HTML"?
LCJ

1
Оце Так! Шаблон всередині JS ... Ніколи про це не думав! Дивовижний!
Роман Лопес

2
Ого, це справді дуже приємно. Я додаю атрибут data-data до кожного шаблону. І отримання даних про ajax для кожного. Це так приємно і врятувало мені стільки часу! Дякую.
Дейві

42

Використовуйте замість шаблону 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 <шаблон>

  • + Його вміст ефективно інертний до активації. По суті, ваша розмітка є прихованою 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/importNode http://caniuse.com/#feat=queryselector

СТВОРЕННЯ ВЕБ-КОМПОНЕНТІВ Створення навчальних посібників веб-компонентів за допомогою шаблонів HTML від Trawersy Media: https://youtu.be/PCWaFLy3VUo


4
templateЕлемент не підтримується Internet Explorer (станом на 2018 рік, IE11). Випробувано на прикладі 580 з w3c.github.io/html/single-page.html .
Роланд

Мені подобається <template>, хоча я б рекомендував використовувати заняття вільно, тому зрозуміло, які реквізити підбираються до чого. Досі потрібні певні навички js для правильного відображення даних у шаблоні, особливо з використанням компонентного підходу до відображення у великих наборах даних. Особисто мені все одно подобається просто будувати HTML у функціях або в ідеалі будувати DOM безпосередньо із самим JS та взагалі передавати HTML (наприклад, як це реагує).
Джош з Карібу

Шаблонний підхід працював для мене добре. Одна моя рекомендація - спершу клонувати шаблон (а не в кінці) та працювати з клонованим об’єктом. В іншому випадку зміни, які ви вносите, відбуваються з самим шаблоном. Якби у вас була умовна логіка, де ви встановлювали деякі властивості / вміст лише деякий час, ці властивості були б присутні у вашому наступному використанні шаблону. Клонуючись перед кожним використанням, ви гарантуєте, що завжди маєте послідовну базу для роботи.
jt.

13

Додайте десь у тіло

<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() );

1
ОП має JSON і хоче надати трохи html, використовуючи цей масив як джерело даних. Як ця відповідь вирішує проблему? Ваша відповідь займає html-вузол і клонує / дублює його, і нічого, що стосується прив'язки даних.
Адріан Іфтоде

Так що я є тим, хто виступає проти.
Адріан Іфтоде

Я дійсно думаю, що ти не допомагаєш отримати кращу відповідь, як ти міг почати з того, що нагадуєш нам про те, що справа в тому, що стосується наших відповідей.
Себастьян Нейра

1
Це справді працює, але це зробити ефективніше .children().clone(), ніж ніж .html(). Швидкість - приблизно 3: 1 для випадкового, який <tr/>я мав на сторінці, використовуючи цей код i=10000; time=performance.now(); while (--i) {$a.clone().append(0 ? $b.html() : $b.children().clone())} performance.now()-time. Співвідношення насправді трохи більше перебільшене, тому що я використовую $ a.clone (), але намагання спорожнити його кожну ітерацію - це скоріше хіт продуктивності, ніж клонування, тому я не знаю, як зробити це більш точним, оскільки функції синхронізації мають власну вартість.
Чіното Вокро

1
Цей підхід поганий. головним чином через те, що ви завантажуєте та аналізуєте вміст шаблону, навіть якщо ви його не використовували. Це занадто велике питання, щоб вважати це правильною відповіддю. Також як хтось інший ментон вище, якщо вам потрібно хоча б використовувати клон замість .html ()
DevWL

3

Інша альтернатива: чисто

Я ним користуюся, і це мені дуже допомогло. Приклад, показаний на їхньому веб-сайті:

HTML

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

JSON

{
  "who": "Hello Wrrrld"
}

Результат

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

2

Для вирішення цієї проблеми я розпізнаю два рішення:

  • Перший - це 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()Замість приховування.

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

    .detach() видаляє елементи з DOM, зберігаючи дані та події живими (.remove () не!).


- Немає проблем! -
iConnor

Оп має JSON і хоче надати трохи html, використовуючи цей масив як джерело даних. Як ця відповідь вирішує проблему? Ваша відповідь займає html-вузол і клонує / дублює його, і нічого, що стосується прив'язки даних.
Адріан Іфтоде

1
Цитую з оп: Я хочу додати копію HTML-коду нижче до елемента контейнера з деякими значеннями. Я вважаю, що це вирішує його проблему.
Себастьян Нейра

І як трактується частина "деяких цінностей"?
Адріан Іфтоде

Ну, це не означає, що це не вирішує проблему. Я вдячний, що ви мені сказали, що мені не вистачає одного з пунктів :) У будь-якому разі, як мені знати, як вставити ці значення, якщо я навіть не знаю, про які значення ми говоримо? Просто погляньте на цю частину Де я можу розмістити цей HTML для повторного використання розумним способом? . Що насправді запитують? Про JSON чи включення HTML?
Себастьян Нейра

1

Дуже хороша відповідь від DevWL про використання нативного елемента шаблону HTML5 . Щоб сприяти цьому хорошому питанню від ОП, я хотів би додати, як використовувати цей templateелемент, використовуючи jQuery, наприклад:

$($('template').html()).insertAfter( $('#somewhere_else') );

Вміст templateфайлу не є html, а просто трактується як дані, тому вам потрібно загортати вміст в об’єкт jQuery, щоб потім отримати доступ до методів jQuery.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.