¿Cómo utilizar underscore.js como motor de plantillas?

262

Estoy tratando de aprender sobre nuevos usos de javascript como lenguaje del servidor y como lenguaje funcional. Hace unos días escuché sobre node.js y express framework. Luego vi sobre underscore.js como un conjunto de funciones de utilidad. Vi esta pregunta en stackoverflow . Dice que podemos usar underscore.js como motor de plantillas. Alguien conoce buenos tutoriales sobre cómo utilizar underscore.js para crear plantillas, especialmente para los fanáticos que tienen menos experiencia con javascript avanzado. Gracias

Knodumi
fuente
12
En defensa de "Luke", la versión mejorada del manual al menos desde mayo no tenía uso avanzado
Shanimal
Acabo de responder una pregunta similar que también beneficiaría su pregunta. stackoverflow.com/questions/28136101/retrieve-column-in-parse/…
jeffdill2

Respuestas:

475

Todo lo que necesita saber sobre la plantilla de subrayado está aquí . Solo 3 cosas a tener en cuenta:

  1. <% %> - para ejecutar un código
  2. <%= %> - para imprimir algún valor en la plantilla
  3. <%- %> - para imprimir algunos valores HTML escapado

De eso se trata todo.

Ejemplo simple:

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

luego tpl({foo: "blahblah"})se representaría en la cadena<h1>Some text: blahblah</h1>

CONJUNTO
fuente
55
No entiendo por qué alguien rechazaría esto, es la respuesta canónica y señala las instrucciones en la página principal del proyecto, es el clásico "enseñar a un hombre a pescar".
Jon z
1
Creo que rechazarían el voto porque la documentación que proporcionan proporciona muy poco sobre cómo mezclar <% y <% = más allá de su ejemplo singular y cómo cambiar de <% = a print () cambia ese patrón. Además, cuando se usa 'interpolar', hay algunos comportamientos extraños que probablemente harían escena con un poco más de explicación. De nuevo, que no se proporciona. Aunque estoy de acuerdo, es una estupidez rechazar el voto.
QueueHammer el
8
3. <% -%> - para imprimir algunos valores con HTML escapado
LeeGee
13
No voté en contra, pero su respuesta no hace nada (aparte de ofrecer un enlace) para explicar cómo usar underscore.js como motor de plantillas. Su respuesta proporciona una "hoja de trucos" rápida quizás para aquellos que ya la obtienen, pero por sí sola, no es una respuesta a la pregunta. Me sorprende que tenga tantos votos a favor como los tiene.
Zach Lysobey
1
-1, la documentación es deficiente en numerosos aspectos. Es casi seguro que el usuario vino aquí después de consultar los documentos. Mala respuesta.
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 Gracias @PHearst!
  • JsFiddle (último)
  • JsFiddle List agrupada por la primera letra (ejemplo complejo con imágenes, llamadas a funciones, sub-plantillas) bifurca! tener una explosión...
  • Demostración de JsFiddle del truco de XSS anotado por @tarun_telang a continuación
  • JsFiddle Un método no estándar para hacer sub-plantillas
Shanimal
fuente
17
Gracias por usar explícitamente la etiqueta de script "text / html" en su ejemplo; Soy nuevo en underscore.js y desafortunadamente he leído mal la documentación; es bueno saber que templateString no siempre tiene que escribirse en línea.
aschyiel
La plantilla no es realmente text/htmlasí que decir que type="text/html"es una mentira, las mentiras pueden causar problemas. Sería mejor con un tipo exacto como text/x-underscore.
mu es demasiado corto el
66
mu, creo que es bueno señalar que no importa. seamos sinceros, todo lo que pones allí es mentira. text / x-underscore es una mentira más grande porque uso lodash, lol :) En el último JsFiddle agregué type="foo/bar"porque quiero que todos sepan que no importa mientras el navegador / servidor no lo reconozca e intente hacer algo con eso Como html no es un tipo de script, me siento bastante seguro con text / html (John Resig lo usa) foo / bar también funciona :)
Shanimal
44
La gente no está de acuerdo conmigo todo el tiempo, hago todo lo posible para no tomarlo como algo personal (incluso cuando es personal :). Me han quemado los efectos secundarios no deseados de un descuido menor una y otra vez, por lo que mi hábito es errar por el lado de la rigidez. Las especificaciones de tipo MIME en realidad reservan */x-*tipos para usos "inventados", no creo que haya un text/underscoretipo en los registros oficiales, así que lo uso text/x-underscoreporque soy paranoico y realmente están tratando de atraparme.
mu es demasiado corto el
1
que se sepa que la demostración XSS ya no funciona porque los navegadores se niegan a ejecutar JS con un tipo
MIME
94

En su forma más simple, lo usarías como:

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

Si va a utilizar una plantilla varias veces, querrá compilarla para que sea más rápida:

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

Personalmente prefiero la sintaxis de estilo bigote. Puede ajustar los marcadores de token de plantilla para usar llaves dobles:

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

var template = _.template('<li>{{ name }}</li>');
malvado
fuente
La sugerencia de interpolación de bigote me ayudó mientras usaba la vista express3 que se procesaba usando ejs. ¡Gracias!
micrub
Para usar plantillas desde la vista, puede tener lo siguiente en el marcado de su página: <script type = "text / template" id = "my-template"> <div> <% - name%> </div> </ script > y luego haga lo siguiente en su JS: var html = _.template ($ ('# my-template'). html (), {name: "John Smith"});
Gaurav Gupta
2
@evilcelery - su interpolatepropina no funcionó, pero esto sí:_.templateSettings = { interpolate: /\{\{\=(.+?)\}\}/g, escape: /\{\{\-(.+?)\}\}/g, evaluate: /\{\{(.+?)\}\}/g };
vsync
28

La documentación para la creación de plantillas es parcial, vi la fuente.

La función _.template tiene 3 argumentos:

  1. Texto de cadena : la cadena de plantilla
  2. Datos del objeto : los datos de evaluación
  3. Configuración de objeto : configuración local, _.templateSettings es el objeto de configuración global

Si no hay datos dado (o nula), de un hacer que la función será devuelto. Tiene 1 argumento:

  1. Datos del objeto : igual que los datos anteriores

Hay 3 patrones de expresiones regulares y 1 parámetro estático en la configuración:

  1. Evaluación de RegExp : "<% code%>" en la cadena de plantilla
  2. Interpolación RegExp : "<% = code%>" en la cadena de plantilla
  3. RegExp escape : "<% - code%>"
  4. Variable de cadena : opcional, el nombre del parámetro de datos en la cadena de plantilla

El código en una sección de evaluación será simplemente evaluado. Puede agregar cadenas desde esta sección con el comando __p + = "mystring" a la plantilla evaluada, pero esto no se recomienda (no es parte de la interfaz de plantillas), use la sección de interpolación en lugar de eso. Este tipo de sección es para agregar bloques como if o for a la plantilla.

El resultado del código en la sección de interpolación se agregará a la plantilla evaluada. Si se devuelve un valor nulo, se agregará una cadena vacía.

La sección de escape escapa html con _.escape en el valor de retorno del código dado. Por lo tanto, es similar a un _.escape (código) en una sección de interpolación , pero se escapa con \ los espacios en blanco como \ n antes de pasar el código al _.escape . No sé por qué es tan importante, está en el código, pero funciona bien con la interpolación y _.escape , que tampoco escapa a los caracteres de espacio en blanco.

De forma predeterminada, el parámetro de datos se pasa por una instrucción with (data) {...} , pero este tipo de evaluación es mucho más lenta que la evaluación con variable con nombre. Entonces nombrar los datos con el parámetro variable es algo bueno ...

Por ejemplo:

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

resultados

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"

Puede encontrar aquí más ejemplos de cómo usar la plantilla y anular la configuración predeterminada: http://underscorejs.org/#template

Al cargar la plantilla tiene muchas opciones, pero al final siempre tiene que convertir la plantilla en una cadena. Puede darlo como una cadena normal como en el ejemplo anterior, o puede cargarlo desde una etiqueta de script y usar la función .html () de jquery, o puede cargarlo desde un archivo separado con el complemento tpl de require.js .

Otra opción para construir el árbol dom con lacónico en lugar de plantillas.

inf3rno
fuente
21

Estoy dando un ejemplo muy 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); 

El resultado sería

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

2) Esta es una plantilla

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

Esto es html

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

Este es el código javascript que contiene el objeto json y pone la plantilla 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
fuente
14

con express es muy fácil. todo lo que necesita es usar el módulo consolidado en el nodo, por lo que debe instalarlo:

npm install consolidate --save

entonces debe cambiar el motor predeterminado a la plantilla html de esta manera:

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

registre el motor de plantilla de subrayado para la extensión html:

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

está hecho !

Ahora para cargar, por ejemplo, una plantilla llamada 'index.html':

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

tal vez necesite instalar el módulo de subrayado.

npm install underscore --save

¡Espero que esto te ayude!

Khalid Ahmada
fuente
12

Quería compartir un hallazgo más importante.

El uso de <% = variable => daría como resultado una vulnerabilidad de secuencias de comandos entre sitios. Por lo tanto, es más seguro usar <% - variable -> en su lugar.

Tuvimos que reemplazar <% = con <% - para evitar ataques de secuencias de comandos entre sitios. No estoy seguro, si esto tendrá algún impacto en el rendimiento

Tarun
fuente
2
+1 Agregué una nota sobre XSS a mi ejemplo. Este es un punto realmente bueno sobre la inyección de información de usuario no higiénica en una página web. ya sea a través de un motor de plantillas o incluso $ .html ().
Shanimal
1

Lodash también es el mismo Primero escribe un guión de la siguiente manera:

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

Ahora escriba algunos JS simples de la siguiente manera:

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

Donde popoup es un div donde desea generar la tabla

Dr.Sai
fuente