J'ai un tableau que je boucle en boucle. Chaque fois qu'une condition est vraie, je souhaite ajouter une copie du code HTML
ci-dessous à un élément conteneur contenant certaines valeurs.
Où puis-je mettre ce code HTML à réutiliser de manière intelligente?
<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
});
});
Vous pouvez décider d'utiliser un moteur de modélisation dans votre projet, tel que:
Si vous ne souhaitez pas inclure une autre bibliothèque, John Resig propose une solution jQuery , similaire à celle ci-dessous.
Les navigateurs et les lecteurs d'écran ignorent les types de script non reconnus:
<script id="hidden-template" type="text/x-custom-template">
<tr>
<td>Foo</td>
<td>Bar</td>
<tr>
</script>
Avec jQuery, ajouter des lignes basées sur le modèle ressemblerait à ceci:
var template = $('#hidden-template').html();
$('button.addRow').click(function() {
$('#targetTable').append(template);
});
Vieille question, mais puisque la question demande "utiliser jQuery", je pensais que je fournirais une option qui vous permet de le faire sans introduire de dépendance du fournisseur.
Bien qu'il existe de nombreux moteurs de gabarit, beaucoup de leurs fonctionnalités ont récemment été désavantagées, avec l'itération (<% for
), les conditionnels (<% if
) et les transformations (<%= myString | uppercase %>
) considérées au mieux comme microlangues et au pire. Les pratiques modernes de création de modèles encouragent simplement la mise en correspondance d'un objet avec sa représentation DOM (ou autre), par ex. ce que nous voyons avec les propriétés mappées aux composants dans ReactJS (en particulier les composants sans état).
Une propriété sur laquelle vous pouvez compter pour conserver le code HTML de votre modèle à côté du reste de votre code HTML consiste à utiliser un <script>
non-exécutable _ type
, par exemple. <script type="text/template">
. Pour votre cas:
<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>
Lors du chargement du document, lisez votre modèle et créez-le en utilisant un simple String#split
var itemTpl = $('script[data-template="listitem"]').text().split(/\$\{(.+?)\}/g);
Notez qu'avec notre jeton, vous l'obtenez au format alternatif [text, property, text, property]
. Cela nous permet de bien le mapper en utilisant un Array#map
, avec une fonction de mappage:
function render(props) {
return function(tok, i) { return (i % 2) ? props[tok] : tok; };
}
Où props
pourrait ressembler à { url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }
.
Rassemblez tout en supposant que vous ayez analysé et chargé votre itemTpl
comme ci-dessus et que vous ayez un tableau items
:
$('.search').keyup(function () {
$('.list-items').append(items.map(function (item) {
return itemTpl.map(render(item)).join('');
}));
});
Cette approche est également à peine jQuery - vous devriez être capable de prendre la même approche en utilisant le javascript Vanilla avec document.querySelector
et .innerHTML
.
Une question à vous poser est la suivante: voulez-vous/avez-vous vraiment besoin de définir des modèles comme des fichiers HTML? Vous pouvez toujours composant + réutiliser un modèle de la même manière que vous réutilisez la plupart des choses que vous voulez répéter: avec une fonction.
Dans es7-land, à l'aide de la déstructuration, des chaînes de modèle et des fonctions de flèche, vous pouvez écrire des fonctions de composants jolies et jolies qui peuvent être facilement chargées à l'aide de la méthode $.fn.html
ci-dessus.
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>
`;
Ensuite, vous pouvez facilement le rendre, même mappé depuis un tableau, comme ceci:
$('.list-items').html([
{ url: '/foo', img: 'foo.png', title: 'Foo item' },
{ url: '/bar', img: 'bar.png', title: 'Bar item' },
].map(Item).join(''));
Oh et note finale: n'oubliez pas de nettoyer vos propriétés transmises à un modèle, si elles sont lues à partir d'une base de données, sinon quelqu'un pourrait passer au format HTML (puis exécuter des scripts, etc.) à partir de votre page.
Étant donné que la réponse acceptée représenterait une méthode de script de surcharge, je souhaiterais en proposer une autre qui, à mon avis, est beaucoup plus propre et plus sûre en raison des risques XSS liés aux scripts de surcharge.
J'ai fait un démo pour vous montrer comment l'utiliser dans une action et comment injecter un modèle dans un autre, l'éditer puis l'ajouter au document DOM.
<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>
// 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);
+ Son contenu est effectivement inerte jusqu'à ce qu'il soit activé. Essentiellement, votre balisage est un DOM masqué et ne s'affiche pas.
+ Tout contenu dans un modèle n'aura pas d'effets secondaires. Les scripts ne s'exécutent pas, les images ne se chargent pas, le son ne joue pas ... tant que le modèle n'est pas utilisé.
+ Le contenu est considéré ne pas être dans le document. L'utilisation de document.getElementById()
ou querySelector()
dans la page principale ne renvoie pas de nœuds enfants d'un modèle.
+ Les modèles peuvent être placés n'importe où dans <head>
, <body>
ou <frameset>
et peuvent contenir tout type de contenu autorisé dans ces éléments. Notez que "n'importe où" signifie que <template>
peut être utilisé en toute sécurité dans des endroits interdits par l'analyseur HTML.
La prise en charge des navigateurs ne devrait pas être un problème, mais si vous souhaitez couvrir toutes les possibilités, vous pouvez effectuer une vérification simple:
Pour détecter les fonctionnalités
<template>
, créez l'élément DOM et vérifiez que la propriété .content existe:
function supportsTemplate() {
return 'content' in document.createElement('template');
}
if (supportsTemplate()) {
// Good to go!
} else {
// Use old templating techniques or libraries.
}
<script>
a display:none
par défaut."text/javascript"
..innerHTML
. L'analyse des chaînes au moment de l'exécution des données fournies par l'utilisateur peut facilement conduire à des vulnérabilités XSS.Article complet: https://www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old
Référence utile: https://developer.mozilla.org/en-US/docs/Web/API/Document/importNodehttp://caniuse.com/#feat=queryselector
Ajouter quelque part dans le corps
<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>
puis créez css
.hide { display: none; }
et ajouter à votre js
$('#output').append( $('.hide').html() );
Autre alternative: Pure
Je l'utilise et cela m'a beaucoup aidé. Un exemple montré sur leur site web:
HTML
<div class="who">
</div>
JSON
{
"who": "Hello Wrrrld"
}
Résultat
<div class="who">
Hello Wrrrld
</div>
Afin de résoudre ce problème, je reconnais deux solutions:
Le premier correspond à AJAX, avec lequel vous devez charger le modèle à partir d’un autre fichier et l’ajouter à chaque fois que vous le souhaitez avec .clone()
.
$.get('url/to/template', function(data) {
temp = data
$('.search').keyup(function() {
$('.list-items').html(null);
$.each(items, function(index) {
$(this).append(temp.clone())
});
});
});
Tenez compte du fait que l'événement doit être ajouté une fois l'ajax terminé pour être sûr que les données sont disponibles!
La seconde serait de l'ajouter directement n'importe où dans le code HTML d'origine, de le sélectionner et de le masquer dans jQuery:
temp = $('.list_group_item').hide()
Vous pouvez ensuite ajouter une nouvelle instance du modèle avec
$('.search').keyup(function() {
$('.list-items').html(null);
$.each(items, function(index) {
$(this).append(temp.clone())
});
});
Identique au précédent, mais si vous ne voulez pas que le modèle reste là, mais juste dans le javascript, je pense que vous pouvez utiliser (ne l'avez pas testé!) .detach()
au lieu de masquer.
temp = $('.list_group_item').detach()
.detach()
supprime les éléments du DOM tout en conservant les données et les événements actifs (ce n'est pas le cas de .remove ()!).