Comment utiliser underscore.js comme moteur de modèle?

262

J'essaie de découvrir les nouveaux usages de javascript en tant que langue côté serveur et en tant que langage fonctionnel. Il y a quelques jours, j'ai entendu parler de node.js et du framework express. Ensuite, j'ai vu le fichier underscore.js comme un ensemble de fonctions utilitaires. J'ai vu cette question sur stackoverflow . Il dit que nous pouvons utiliser underscore.js comme moteur de modèle. tout le monde connaît de bons tutoriels sur la façon d'utiliser underscore.js pour les modèles, en particulier pour les débutants qui ont moins d'expérience avec le javascript avancé. Merci

knodumi
la source
12
Dans la défense de "Luke", la version améliorée du manuel au moins aussi tôt que mai n'avait aucune utilisation avancée
Shanimal
Je viens de répondre à une question similaire qui bénéficierait également à votre question. stackoverflow.com/questions/28136101/retrieve-column-in-parse/…
jeffdill2

Réponses:

475

Tout ce que vous devez savoir sur le modèle de soulignement est ici . Seulement 3 choses à garder à l'esprit:

  1. <% %> - pour exécuter du code
  2. <%= %> - pour imprimer une valeur dans le modèle
  3. <%- %> - pour imprimer certaines valeurs HTML échappées

C'est tout.

Exemple simple:

var tpl = _.template("<h1>Some text: <%= foo %></h1>");

alors tpl({foo: "blahblah"})serait rendu à la chaîne<h1>Some text: blahblah</h1>

ENSEMBLE
la source
55
Je ne comprends pas pourquoi quelqu'un voterait contre cela, c'est la réponse canonique et pointe vers les instructions sur la page d'accueil du projet, c'est le classique "apprendre à un homme à pêcher".
Jon z
1
Je pense qu'ils voteraient vers le bas parce que la documentation qu'ils fournissent donne très peu sur la façon de mélanger <% et <% = au-delà de leur exemple singulier et comment le passage de <% = à print () change ce modèle. De plus, lorsque vous utilisez «interpoler», il existe des comportements étranges qui rendraient probablement la scène avec un peu plus d'explications. Encore une fois, ce qui n'est pas fourni. Bien que je sois d'accord, c'est une chose stupide de voter contre.
QueueHammer
8
3. <% -%> - pour imprimer certaines valeurs avec HTML échappé
LeeGee
13
Je n'ai pas downvote, mais votre réponse ne fait rien (à part offrir un lien) pour expliquer comment utiliser underscore.js comme moteur de modèle. Votre réponse fournit une "feuille de triche" rapide peut-être pour ceux qui l'ont déjà, mais en soi, ce n'est pas une réponse à la question. Je suis surpris qu'il ait autant de votes positifs que cela.
Zach Lysobey
1
-1, la documentation est déficiente à plusieurs égards. Il est presque certain que l'utilisateur est venu ici après avoir consulté la documentation. Mauvaise réponse.
Matt Parkins
199
<!-- Install jQuery and underscore -->

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script>

<!-- Create your template -->
<script type="foo/bar" id='usageList'>
<table cellspacing='0' cellpadding='0' border='1' >
    <thead>
      <tr>
        <th>Id</th>
        <th>Name</th>
      </tr>
    </thead>
    <tbody>
      <%
        // repeat items 
        _.each(items,function(item,key,list){
          // create variables
          var f = item.name.split("").shift().toLowerCase();
      %>
        <tr>
          <!-- use variables -->
          <td><%= key %></td>
          <td class="<%= f %>">
            <!-- use %- to inject un-sanitized user input (see 'Demo of XSS hack') -->
            <h3><%- item.name %></h3>
            <p><%- item.interests %></p>
          </td>
        </tr>
      <%
        });
      %>
    </tbody>
  </table>
</script>

<!-- Create your target -->

<div id="target"></div>

<!-- Write some code to fetch the data and apply template -->

<script type="text/javascript">
  var items = [
    {name:"Alexander", interests:"creating large empires"},
    {name:"Edward", interests:"ha.ckers.org <\nBGSOUND SRC=\"javascript:alert('XSS');\">"},
    {name:"..."},
    {name:"Yolando", interests:"working out"},
    {name:"Zachary", interests:"picking flowers for Angela"}
  ];
  var template = $("#usageList").html();
  $("#target").html(_.template(template,{items:items}));
</script>
  • JsFiddle Merci @PHearst!
  • JsFiddle (dernier)
  • JsFiddle List groupé par première lettre (exemple complexe avec images, appels de fonction, sous-modèles) fork it! amusez-vous ...
  • La démo JsFiddle du hack XSS notée par @tarun_telang ci-dessous
  • JsFiddle Une méthode non standard pour faire des sous-modèles
Shanimal
la source
17
Merci d'utiliser explicitement la balise de script "text / html" dans votre exemple; Je suis nouveau sur underscore.js et j'ai malheureusement mal lu la documentation - il est bon de savoir que le templateString ne doit pas toujours être écrit en ligne.
aschyiel
Le modèle n'est pas vraiment text/htmlsi dire que type="text/html"c'est un mensonge, les mensonges peuvent causer des problèmes. Vous seriez mieux avec un type précis tel que text/x-underscore.
mu est trop court
6
mu, je pense qu'il est bon de souligner que cela n'a pas d'importance. avouons-le, tout ce que vous y mettez est un mensonge. text / x-underscore est un plus grand mensonge parce que j'utilise lodash, lol :) Dans le dernier JsFiddle, j'ai ajouté type="foo/bar"parce que je veux que tout le monde sache que cela n'a pas d'importance tant que le navigateur / serveur ne le reconnaît pas et essaie en faire quelque chose. Puisque le html n'est pas un type de script, je me sens assez en sécurité avec text / html (John Resig l'utilise) foo / bar fonctionne aussi :)
Shanimal
4
Les gens sont toujours en désaccord avec moi, je fais de mon mieux pour ne pas le prendre personnellement (même quand c'est personnel :). J'ai été brûlé par des effets secondaires involontaires de négligence mineure, encore et encore, donc mon habitude est que ce soit du côté de la rigueur. Les spécifications de type MIME réservent en fait des */x-*types pour des utilisations "inventées", je ne pense pas qu'il y ait un text/underscoretype dans les registres officiels, donc j'utilise text/x-underscoreparce que je suis paranoïaque et ils sont vraiment là pour me trouver.
mu est trop court le
1
faites savoir que la démo XSS ne fonctionne plus parce que les navigateurs refusent d'exécuter JS avec un type de
mime
94

Dans sa forme la plus simple, vous l'utiliseriez comme:

var html = _.template('<li><%= name %></li>', { name: 'John Smith' });
//html is now '<li>John Smith</li>'   

Si vous allez utiliser un modèle plusieurs fois, vous voudrez le compiler pour qu'il soit plus rapide:

var template = _.template('<li><%= name %></li>');

var html = [];
for (var key in names) {
    html += template({ name: names[i] });
}

console.log(html.join('')); //Outputs a string of <li> items

Personnellement, je préfère la syntaxe du style Moustache. Vous pouvez ajuster les marqueurs de jeton de modèle pour utiliser des accolades doubles:

_.templateSettings.interpolate = /\{\{(.+?)\}\}/g;

var template = _.template('<li>{{ name }}</li>');
evilcelery
la source
Astuce d'interpolation de moustache m'a aidé lors de l'utilisation de la vue express3 qui a rendu en utilisant ejs Merci!
micrub
Pour utiliser des modèles à partir de la vue, vous pouvez avoir les éléments suivants dans le balisage de votre page: <script type = "text / template" id = "my-template"> <div> <% - name%> </div> </ script > puis procédez comme suit dans votre JS: var html = _.template ($ ('# my-template'). html (), {name: "John Smith"});
Gaurav Gupta
2
@evilcelery - votre interpolateconseil n'a pas fonctionné, mais cela a fonctionné:_.templateSettings = { interpolate: /\{\{\=(.+?)\}\}/g, escape: /\{\{\-(.+?)\}\}/g, evaluate: /\{\{(.+?)\}\}/g };
vsync
28

La documentation pour les modèles est partielle, j'ai regardé la source.

La fonction _.template a 3 arguments:

  1. Texte de chaîne : la chaîne de modèle
  2. Données d' objet : les données d'évaluation
  3. Paramètres d' objet : paramètres locaux, le _.templateSettings est l'objet de paramètres globaux

Si aucune donnée (ou null) n'est donnée, une fonction de rendu sera retournée. Il a 1 argument:

  1. Données d' objet : identiques aux données ci-dessus

Il y a 3 modèles d'expression régulière et 1 paramètre statique dans les paramètres:

  1. RegExp évalue : "<% code%>" dans la chaîne de modèle
  2. Interpolation RegExp : "<% = code%>" dans la chaîne de modèle
  3. RegExp échapper : "<% -% de code>"
  4. Variable de chaîne : facultatif, le nom du paramètre de données dans la chaîne de modèle

Le code dans une section d' évaluation sera simplement évalué. Vous pouvez ajouter une chaîne de cette section avec la commande __p + = "mystring" au modèle évalué, mais ce n'est pas recommandé (ne fait pas partie de l'interface de modèles), utilisez la section interpoler à la place. Ce type de section sert à ajouter des blocs comme if ou for au modèle.

Le résultat du code dans la section interpoler sera ajouté au modèle évalué. Si null est renvoyé, une chaîne vide sera ajoutée.

La section d' échappement échappe html avec _.escape sur la valeur de retour du code donné. Donc, c'est similaire à un _.escape (code) dans une section interpolée , mais il s'échappe avec \ les espaces comme \ n avant de passer le code au _.escape . Je ne sais pas pourquoi est-ce important, c'est dans le code, mais cela fonctionne bien avec l' interpolation et le _.escape - qui n'échappe pas aux caractères d'espace blanc - aussi.

Par défaut, le paramètre de données est transmis par une instruction with (data) {...} , mais ce type d'évaluation est beaucoup plus lent que l'évaluation avec la variable nommée. Nommer les données avec le paramètre variable est donc quelque chose de bien ...

Par exemple:

var html = _.template(
    "<pre>The \"<% __p+=_.escape(o.text) %>\" is the same<br />" +
        "as the  \"<%= _.escape(o.text) %>\" and the same<br />" +
        "as the \"<%- o.text %>\"</pre>",
    {
        text: "<b>some text</b> and \n it's a line break"
    },
    {
        variable: "o"
    }
);

$("body").html(html);

résultats

The "<b>some text</b> and 
 it's a line break" is the same
as the "<b>some text</b> and 
 it's a line break" and the same
as the "<b>some text</b> and 
 it's a line break"

Vous pouvez trouver ici plus d'exemples sur la façon d'utiliser le modèle et de remplacer les paramètres par défaut: http://underscorejs.org/#template

En chargeant le modèle, vous avez de nombreuses options, mais à la fin, vous devez toujours convertir le modèle en chaîne. Vous pouvez le donner comme une chaîne normale comme l'exemple ci-dessus, ou vous pouvez le charger à partir d'une balise de script et utiliser la fonction .html () de jquery, ou vous pouvez le charger à partir d'un fichier séparé avec le plugin tpl de require.js .

Une autre option pour construire l'arbre dom avec laconique au lieu de modeler.

inf3rno
la source
21

Je donne un exemple très simple

1)

var data = {site:"mysite",name:"john",age:25};
var template = "Welcome you are at <%=site %>.This has been created by <%=name %> whose age is <%=age%>";
var parsedTemplate = _.template(template,data);
console.log(parsedTemplate); 

Le résultat serait

Welcome you are at mysite.This has been created by john whose age is 25.

2) Ceci est un modèle

   <script type="text/template" id="template_1">
       <% _.each(items,function(item,key,arr) { %>
          <li>
             <span><%= key %></span>
             <span><%= item.name %></span>
             <span><%= item.type %></span>
           </li>
       <% }); %>
   </script>

C'est html

<div>
  <ul id="list_2"></ul>
</div>

Ceci est le code javascript qui contient l'objet json et met le modèle en html

   var items = [
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       },
       {
          name:"name1",
          type:"type1"
       } 
   ];
  $(document).ready(function(){
      var template = $("#template_1").html();
      $("#list_2").html(_.template(template,{items:items}));
  });

dinesh_malhotra
la source
14

avec express c'est si facile. tout ce dont vous avez besoin est d'utiliser le module de consolidation sur le nœud, vous devez donc l'installer:

npm install consolidate --save

alors vous devez changer le moteur par défaut en modèle html par ceci:

app.set('view engine', 'html');

enregistrez le moteur de modèle de soulignement pour l'extension html:

app.engine('html', require('consolidate').underscore);

c'est fait !

Maintenant pour charger par exemple un modèle appelé 'index.html':

res.render('index', { title : 'my first page'});

vous devrez peut-être installer le module de soulignement.

npm install underscore --save

J'espère que cela vous a aidé!

Khalid Ahmada
la source
12

Je voulais partager une autre conclusion importante.

l'utilisation de <% = variable => entraînerait une vulnérabilité de script intersite. Il est donc plus sûr d'utiliser à la place <% - variable ->.

Nous avons dû remplacer <% = par <% - pour empêcher les attaques de script intersite. Je ne sais pas si cela aura un impact sur les performances

Tarun
la source
2
+1 J'ai ajouté une note sur XSS à mon exemple. C'est un très bon point sur l'injection d'informations utilisateur non désinfectées dans une page Web. soit via un moteur de template ou même $ .html ().
Shanimal le
1

Lodash est aussi le même Premier écrit un script comme suit:

<script type="text/template" id="genTable">
<table cellspacing='0' cellpadding='0' border='1'>
        <tr>
            <% for(var prop in users[0]){%>
            <th><%= prop %> </th>
            <% }%>
        </tr>
        <%_.forEach(users, function(user) { %>
            <tr>
                 <% for(var prop in user){%>
                    <td><%= user[prop] %> </td>
                <% }%>

            </tr>
        <%})%>
</table>

Maintenant, écrivez quelques JS simples comme suit:

var arrOfObjects = [];
for (var s = 0; s < 10; s++) {
    var simpleObject = {};
    simpleObject.Name = "Name_" + s;
    simpleObject.Address = "Address_" + s;
    arrOfObjects[s] = simpleObject;
}
var theObject = { 'users': arrOfObjects }
var compiled = _.template($("#genTable").text());
var sigma = compiled({ 'users': myArr });

$(sigma).appendTo("#popup");

Où popoup est un div où vous souhaitez générer la table

Dr.Sai
la source