Definieren einer HTML-Vorlage zum Anhängen mit JQuery

125

Ich habe ein Array, das ich durchlaufe. Jedes Mal, wenn eine Bedingung erfüllt ist, möchte ich eine Kopie des folgenden HTMLCodes an ein Containerelement mit einigen Werten anhängen .

Wo kann ich diesen HTML-Code auf intelligente Weise wiederverwenden?

<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
    });
});
Patrick Reck
quelle
2
Wenn Sie nach einer intelligenten Methode suchen, fügen Sie alle Ihre Informationen in einem einzigen DIV ein und gestalten Sie sie. Erstellen Sie keine zahlreichen Tabellen mit nur zwei Zellen, sondern wickeln Sie sie nicht in Anker ein.
Sergey Snegirev
3
OP ist offensichtlich an richtigen Codierungspraktiken interessiert (Lob!), Deshalb wollte ich helfen. Wenn ich zum eigentlichen Problem beitragen wollte, würde ich eine Antwort posten. Ich bin sicher, dass jemand zustimmt, dass die Verwendung einer vollständigen Zwei-Zellen-Tabelle zum Positionieren eines Bildes und eines Textes kaum gerechtfertigt ist, abgesehen von einigen wirklich exotischen Anforderungen (IE4?)
Sergey Snegirev
1
@BrianG. Das Posten eines Kommentars bedeutet jedoch nicht wirklich, dass Sie sich auf eine Tangente einlassen. Ich bin damit einverstanden, dass Kommentare ein geeigneter Ort für diese sind (solange sie noch relevant sind), aber sie eignen sich auch für Drive-by-Hinweise von Personen, die noch keine Zeit haben, sie zu einer Antwort zu erweitern. Es ist hilfreich für das OP, klar zu machen, was Sie tun.
Millimoose
Niemand hat deine Frage beantwortet, Patrick?
Sebastian Neira

Antworten:

164

Sie können sich dafür entscheiden, in Ihrem Projekt eine Vorlagen-Engine zu verwenden, z. B.:

Wenn Sie keine weitere Bibliothek einbinden möchten, bietet John Resig eine jQuery-Lösung an , die der folgenden ähnelt.


Browser und Screenreader ignorieren nicht erkannte Skripttypen:

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

Wenn Sie mit jQuery Zeilen basierend auf der Vorlage hinzufügen, ähnelt dies:

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

$('button.addRow').click(function() {
    $('#targetTable').append(template);
});
Mathijs Flietstra
quelle
@MaksimLuzik ist richtig. Moustache (beachten Sie die Schreibweise der Marke) ist leichter und wird in den OP-Code eingefügt. Der Lenker verfügt jedoch über mehr Funktionen für die Handhabung von Arrays und bietet möglicherweise am Ende eine ausreichendere Lösung. Hier ist ein schöner Vergleichsartikel: blog.cubettech.com/…
Michael Scheper
13
Beispiel für die Bearbeitung der Vorlage hier: jsfiddle.net/meehanman/7vw8bc84
Dean Meehan
175

Alte Frage, aber da die Frage "using jQuery" lautet, dachte ich, ich würde eine Option bereitstellen, mit der Sie dies tun können, ohne eine Herstellerabhängigkeit einzuführen.

Zwar gibt es eine Vielzahl von Template-Engines, doch viele ihrer Funktionen haben sich in letzter Zeit als ungünstig erwiesen , wobei Iteration ( <% for), Bedingungen ( <% if) und Transformationen ( <%= myString | uppercase %>) bestenfalls als Mikrosprache und im schlimmsten Fall als Anti-Patterns angesehen werden. Moderne Vorlagenpraktiken empfehlen, ein Objekt einfach seiner DOM-Darstellung (oder einer anderen Darstellung) zuzuordnen, z. B. dem, was wir mit Eigenschaften sehen, die Komponenten in ReactJS zugeordnet sind (insbesondere zustandslose Komponenten).

Vorlagen in HTML

Eine Eigenschaft, auf die Sie sich verlassen können, um den HTML-Code für Ihre Vorlage neben dem Rest Ihres HTML-Codes zu halten, ist die Verwendung eines nicht ausgeführten <script> type, z <script type="text/template">. Für Ihren Fall:

<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>

Lesen Sie beim Laden des Dokuments Ihre Vorlage und markieren Sie sie mit einem einfachen Token String#split

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

Beachten Sie, dass Sie unser Token im alternierenden [text, property, text, property]Format erhalten. Auf diese Weise können wir es Array#mapmit einer Mapping-Funktion gut abbilden:

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

Wo propskönnte so aussehen { url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }.

Alles zusammen, vorausgesetzt, Sie haben Ihre Daten itemTplwie oben beschrieben analysiert und geladen und haben ein itemsArray im Gültigkeitsbereich:

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

Dieser Ansatz ist auch nur knapp jQuery - Sie sollten in der Lage sein, den gleichen Ansatz mit Vanille-Javascript mit document.querySelectorund zu verfolgen .innerHTML.

jsfiddle

Vorlagen in JS

Eine Frage, die Sie sich stellen sollten, lautet: Möchten / müssen Sie Vorlagen wirklich als HTML-Dateien definieren? Sie können eine Vorlage jederzeit so komponieren und wiederverwenden, wie Sie die meisten Dinge, die Sie wiederholen möchten, wiederverwenden würden: mit einer Funktion.

In es7-land können Sie mithilfe von Destrukturierung, Vorlagenzeichenfolgen und Pfeilfunktionen geradezu hübsch aussehende Komponentenfunktionen schreiben, die mit der $.fn.htmlobigen Methode einfach geladen werden können .

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>
`;

Dann können Sie es einfach rendern, sogar aus einem Array, wie folgt:

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

Oh und letzter Hinweis: Vergessen Sie nicht, Ihre an eine Vorlage übergebenen Eigenschaften zu bereinigen, wenn sie aus einer Datenbank gelesen wurden oder jemand HTML von Ihrer Seite übergeben (und dann Skripte usw. ausführen) könnte.

Josh aus Qaribou
quelle
1
Schöne Template Engine.
Arthur Castro
40
Ihre Vorlagen im JS- Bereich sind die Bombe
BigRon
2
Könnten Sie bitte eine Demo / Geige für den "Templates Inside HTML" -Ansatz hinzufügen?
LCJ
1
Beeindruckend! Vorlage in JS ... Daran habe ich nie gedacht! Tolle!
Roman Lopez
2
Wow, das ist wirklich sehr schön. Ich füge jeder Vorlage ein Daten-URL-Attribut hinzu. Und Ajax-Daten für jeden abrufen. Das ist so schön und hat mir so viel Zeit gespart! Danke dir.
Davey
42

Verwenden Sie stattdessen eine HTML-Vorlage!

Da die akzeptierte Antwort eine Überladungsskriptmethode darstellen würde, möchte ich eine andere vorschlagen, die meiner Meinung nach aufgrund der XSS-Risiken, die mit dem Überladen von Skripten einhergehen, viel sauberer und sicherer ist.

Ich habe eine Demo erstellt , um Ihnen zu zeigen, wie Sie sie in einer Aktion verwenden und wie Sie eine Vorlage in eine andere einfügen, bearbeiten und dann zum Dokument-DOM hinzufügen.

Beispiel 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>

Beispiel 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 <Vorlage>

  • + Sein Inhalt ist bis zur Aktivierung effektiv inert. Im Wesentlichen ist Ihr Markup DOM versteckt und wird nicht gerendert.

  • + Inhalte in einer Vorlage haben keine Nebenwirkungen. Skripte werden nicht ausgeführt, Bilder werden nicht geladen, Audio wird nicht abgespielt ... bis die Vorlage verwendet wird.

  • + Inhalt wird als nicht im Dokument enthalten angesehen. Wenn Sie document.getElementById()oder querySelector()auf der Hauptseite verwenden, werden keine untergeordneten Knoten einer Vorlage zurückgegeben.

  • + Vorlagen können überall innerhalb des platziert werden <head>, <body>oder , <frameset>und jede Art von Inhalt enthalten können , die in diesen Elementen erlaubt. Beachten Sie, dass "überall" bedeutet, dass <template>es sicher an Orten verwendet werden kann, die der HTML-Parser nicht zulässt.

Zurückfallen

Browser-Unterstützung sollte kein Problem sein, aber wenn Sie alle Möglichkeiten abdecken möchten, können Sie eine einfache Überprüfung durchführen:

<template>Erstellen Sie zum Erkennen von Funktionen das DOM-Element und überprüfen Sie, ob die Eigenschaft .content vorhanden ist:

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

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

Einige Einblicke in das Überladen von Skriptmethoden

  • + Es wird nichts gerendert - der Browser rendert diesen Block nicht, da das <script>Tag display:nonestandardmäßig vorhanden ist.
  • + Inert - Der Browser analysiert den Skriptinhalt nicht als JS, da sein Typ auf etwas anderes als festgelegt ist "text/javascript".
  • -Sicherheitsprobleme - fördert die Verwendung von .innerHTML. Das Parsen von vom Benutzer bereitgestellten Daten zur Laufzeit von Zeichenfolgen kann leicht zu XSS-Schwachstellen führen.

Vollständiger Artikel: https://www.html5rocks.com/de/tutorials/webcomponents/template/#toc-old

Nützliche Referenz: https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode http://caniuse.com/#feat=queryselector

ERSTELLEN VON WEBKOMPONENTEN Erstellen eines Tutorials für benutzerdefinierte Webkomponenten mithilfe von HTML-Vorlagen von Trawersy Media: https://youtu.be/PCWaFLy3VUo

DevWL
quelle
4
Das templateElement wird von Internet Explorer nicht unterstützt (Stand 2018, IE11). Getestet mit Beispiel 580 von w3c.github.io/html/single-page.html .
Roland
Ich mag das <template>, obwohl ich empfehlen würde, Klassen großzügig zu verwenden, damit klar ist, welche Requisiten auf was eingestellt werden. Es sind noch einige Kenntnisse erforderlich, um Ihre Daten ordnungsgemäß in die Vorlage abzubilden, insbesondere mithilfe eines komponentenartigen Ansatzes für die Zuordnung in großen Datenmengen. Persönlich mag ich es immer noch, nur den HTML-Code in Funktionen zu erstellen oder im Idealfall das DOM direkt mit JS selbst zu erstellen und ganz auf HTML zu verzichten (z. B. wie React es macht).
Josh von Qaribou
Der Template-Ansatz hat bei mir gut funktioniert. Eine Empfehlung, die ich habe, ist, die Vorlage zuerst (und nicht am Ende) zu klonen und mit dem geklonten Objekt zu arbeiten. Andernfalls werden die von Ihnen vorgenommenen Änderungen an der Vorlage selbst vorgenommen. Wenn Sie eine bedingte Logik hätten, bei der Sie einige Eigenschaften / Inhalte nur zeitweise festlegen, wären diese Eigenschaften bei Ihrer nächsten Verwendung der Vorlage vorhanden. Durch das Klonen vor jeder Verwendung stellen Sie sicher, dass Sie immer eine konsistente Basis haben, von der aus Sie arbeiten können.
jt.
13

Fügen Sie irgendwo im Körper hinzu

<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>

dann erstellen Sie CSS

.hide { display: none; }

und füge zu deinem js hinzu

$('#output').append( $('.hide').html() );
Mateusz Nowak
quelle
1
Das OP hat einen JSON und möchte HTML mit diesem Array als Datenquelle rendern. Wie geht diese Antwort das Problem an? Ihre Antwort nimmt einen HTML-Knoten und klont / dupliziert ihn und nichts im Zusammenhang mit der Datenbindung.
Adrian Iftode
Ich bin es also, der abstimmt.
Adrian Iftode
Ich denke wirklich, dass Sie nicht dazu beitragen, eine bessere Antwort zu erhalten, da Sie uns zunächst daran erinnern könnten, dass der Punkt weiter ging als das, was in unseren Antworten angesprochen wurde.
Sebastian Neira
1
Dies funktioniert zwar, ist jedoch effizienter .children().clone()als .html(). Die Geschwindigkeit beträgt ungefähr 3: 1 für einen Zufall, den <tr/>ich mit diesem Code auf einer Seite hatte i=10000; time=performance.now(); while (--i) {$a.clone().append(0 ? $b.html() : $b.children().clone())} performance.now()-time. Das Verhältnis ist tatsächlich etwas übertrieben, weil ich $ a.clone () verwende, aber der Versuch, es bei jeder Iteration zu leeren, ist eher ein Leistungseinbruch als das Klonen, daher bin ich mir nicht sicher, wie ich es genauer machen soll, weil Timing-Funktionen haben ihre eigenen Kosten.
Chinoto Vokro
1
Dieser Ansatz ist schlecht. hauptsächlich, weil Sie Vorlageninhalte herunterladen und analysieren, auch wenn Sie sie nicht verwendet haben. Dies ist ein zu großes Problem, um dies als gültige Antwort zu betrachten. Auch als jemand anderes oben erwähnt, wenn Sie mindestens Klon anstelle von .html () verwenden müssen
DevWL
3

Andere Alternative: Rein

Ich benutze es und es hat mir sehr geholfen. Ein Beispiel auf ihrer Website gezeigt:

HTML

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

JSON

{
  "who": "Hello Wrrrld"
}

Ergebnis

<div class="who">
  Hello Wrrrld
</div>
Alditis
quelle
2

Um dieses Problem zu lösen, erkenne ich zwei Lösungen:

  • Der erste geht mit AJAX, mit dem Sie die Vorlage aus einer anderen Datei laden und jedes Mal hinzufügen müssen, wenn Sie möchten .clone().

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

    Berücksichtigen Sie, dass das Ereignis nach Abschluss des Ajax hinzugefügt werden sollte, um sicherzustellen, dass die Daten verfügbar sind!

  • Die zweite Möglichkeit wäre, es direkt an einer beliebigen Stelle im ursprünglichen HTML-Code hinzuzufügen, auszuwählen und in jQuery auszublenden:

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

    Sie können nach dem Hinzufügen einer neuen Instanz der Vorlage mit

    $('.search').keyup(function() {
        $('.list-items').html(null);
    
        $.each(items, function(index) {
            $(this).append(temp.clone())
        });
    });
  • Wie die vorherige, aber wenn Sie nicht möchten, dass die Vorlage dort bleibt, sondern nur im Javascript, können Sie sie verwenden (haben sie nicht getestet!), .detach()Anstatt sie auszublenden.

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

    .detach() Entfernt Elemente aus dem DOM, während die Daten und Ereignisse am Leben bleiben (.remove () nicht!).

Sebastian Neira
quelle
-- Kein Problem! -
iConnor
Die Operation hat einen JSON und möchte HTML mit diesem Array als Datenquelle rendern. Wie geht diese Antwort das Problem an? Ihre Antwort nimmt einen HTML-Knoten und klont / dupliziert ihn und nichts im Zusammenhang mit der Datenbindung.
Adrian Iftode
1
Ich zitiere aus op: Ich möchte eine Kopie des folgenden HTML-Codes an ein Containerelement mit einigen Werten anhängen. Ich glaube, das spricht sein Problem an.
Sebastian Neira
Und wie wird der Teil "einige Werte" behandelt?
Adrian Iftode
Nun, das heißt nicht, dass das Problem nicht behoben wird. Ich weiß es zu schätzen, dass Sie mir gesagt haben, dass mir einer der Punkte gefehlt hat :) Wie soll ich wissen, wie man diese Werte einfügt, wenn ich nicht einmal weiß, über welche Werte wir sprechen? Schauen Sie sich diesen Teil an. Wo kann ich diesen HTML-Code auf intelligente Weise wiederverwenden? . Was wird wirklich gefragt? Über den JSON oder die HTML-Aufnahme?
Sebastian Neira
1

Sehr gute Antwort von DevWL zur Verwendung des nativen HTML5- Vorlagenelements . Um zu dieser guten Frage aus dem OP beizutragen, möchte ich hinzufügen, wie dieses templateElement mit jQuery verwendet wird, zum Beispiel:

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

Der Inhalt von templateist nicht HTML, sondern wird nur als Daten behandelt. Sie müssen den Inhalt also in ein jQuery-Objekt einschließen, um dann auf die Methoden von jQuery zugreifen zu können.

Jacques
quelle