Como usar o underscore.js como um mecanismo de modelo?


262

Estou tentando aprender sobre os novos usos do javascript como uma linguagem do lado do servidor e como uma linguagem funcional. Alguns dias atrás, ouvi falar do node.js e do framework express. Então eu vi o underscore.js como um conjunto de funções utilitárias. Eu vi essa pergunta no stackoverflow . Ele diz que podemos usar o underscore.js como um mecanismo de modelo. alguém conhece bons tutoriais sobre como usar underscore.js para modelagem, especialmente para biginners que têm menos experiência com javascript avançado. obrigado


12
Na defesa de "Luke", a versão aprimorada do manual pelo menos em maio não tinha uso avançado
Shanimal

Acabei de responder a uma pergunta semelhante que também beneficiaria sua pergunta. stackoverflow.com/questions/28136101/retrieve-column-in-parse/...
jeffdill2

Respostas:


475

Tudo o que você precisa saber sobre o modelo de sublinhado está aqui . Apenas três coisas a serem lembradas:

  1. <% %> - para executar algum código
  2. <%= %> - para imprimir algum valor no modelo
  3. <%- %> - para imprimir alguns valores que o HTML escapou

É tudo sobre isso.

Exemplo simples:

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

então tpl({foo: "blahblah"})seria renderizado para a string<h1>Some text: blahblah</h1>


55
Não entendo por que alguém votaria contra isso, é a resposta canônica e aponta para as instruções na página inicial do projeto, é o clássico "ensinar um homem a pescar".
Jon z

1
Eu acho que eles votariam negativamente porque a documentação que eles fornecem dá muito pouco em como misturar <% e <% = além de seu exemplo singular e como mudar de <% = para print () altera esse padrão. Além disso, ao usar 'interpolar', existem alguns comportamentos estranhos que provavelmente criariam cenas com um pouco mais de explicação. Novamente, o que não é fornecido. Embora eu concorde, é uma coisa estúpida negar o voto.
QueueHammer

8
3. <% -%> - para imprimir alguns valores com HTML escapado
LeeGee 5/12/12

13
Não diminuí a votação, mas sua resposta não faz nada (além de oferecer um link) para explicar como usar o underscore.js como um mecanismo de modelo. Sua resposta fornece uma rápida "dica", talvez para quem já a recebeu, mas, por si só, não é uma resposta para a pergunta. Estou surpreso que tenha tantos votos quanto ele.
Zach Lysobey

1
-1, a documentação é deficiente em vários aspectos. É quase certo que o usuário veio aqui após consultar os documentos. Má resposta.
Matt Parkins 14/05

198
<!-- 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 Obrigado @PHearst!
  • JsFiddle (mais recente)
  • A lista JsFiddle agrupada pela primeira letra (exemplo complexo com imagens, chamadas de função, submodelos) bifurca-se! Divirta-se muito...
  • JsFiddle Demo do XSS hack observado por @tarun_telang abaixo
  • JsFiddle Um método não padrão para criar submodelos

17
Obrigado por usar explicitamente a tag de script "text / html" no seu exemplo; Sou iniciante no underscore.js e, infelizmente, interpretei mal a documentação - é bom saber que o templateString nem sempre precisa ser escrito em linha.
Aschyiel #

Na verdade, o modelo não é text/htmltão type="text/html"mentiroso, mentiras podem causar problemas. Você seria melhor com um tipo preciso como text/x-underscore.
mu é muito curto

6
mu, acho bom ressaltar que isso não importa. vamos ser sinceros, qualquer coisa que você colocar lá é mentira. text / x-underscore é uma mentira maior porque eu uso o lodash, lol :) No último JsFiddle eu adicionei type="foo/bar"porque quero que todos saibam que isso não importa, desde que o navegador / servidor não o reconheça e tente fazer algo com isso. Desde html não é um tipo de roteiro, me sinto bastante seguro com text / html (John Resig usa-lo) obras foo / bar, bem :)
Shanimal

4
As pessoas discordam de mim o tempo todo, faço o possível para não levar para o lado pessoal (mesmo quando é pessoal). Fui queimado por efeitos colaterais não intencionais de pequenas imperfeições repetidas vezes, de modo que meu hábito é errar do lado do rigor. As especificações do tipo MIME, na verdade, reservam */x-*tipos para usos "inventados", não acho que exista um text/underscoretipo nos registros oficiais, então uso text/x-underscoreporque sou paranóico e eles realmente querem me pegar.
mu é muito curto

1
deixá-lo ser conhecido que o XSS demonstração já não funciona porque os navegadores recusar a execução de JS com um mimetype incorreta
nickford

94

Em sua forma mais simples, você usaria como:

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

Se você usar um modelo algumas vezes, será necessário compilá-lo para que seja mais rápido:

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

Pessoalmente, prefiro a sintaxe do estilo Bigode. Você pode ajustar os marcadores de token do modelo para usar chaves duplas:

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

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

A dica de interpolação do bigode me ajudou a usar a exibição express3 que renderizava usando o ejs. Obrigado!
micrub

Para usar modelos da visualização, você pode ter o seguinte na marcação da página: <script type = "text / template" id = "my-template"> <div> <% - nome%> </div> </ script > e faça o seguinte em seu JS: var html = _.template ($ ('# my-template'). html (), {name: "John Smith"});
Gaurav Gupta

2
@evilcelery - sua interpolatedica não funcionou, mas foi isso:_.templateSettings = { interpolate: /\{\{\=(.+?)\}\}/g, escape: /\{\{\-(.+?)\}\}/g, evaluate: /\{\{(.+?)\}\}/g };
vsync

28

A documentação para o modelo é parcial, observei a fonte.

A função _.template possui 3 argumentos:

  1. String de texto : o modelo de cadeia
  2. Dados do objeto : os dados da avaliação
  3. Configurações do objeto : configurações locais, o _.templateSettings é o objeto de configurações globais

Se nenhum dado (ou nulo) for fornecido, uma função de renderização será retornada. Tem 1 argumento:

  1. Dados do objeto : iguais aos dados acima

Existem 3 padrões de regex e 1 parâmetro estático nas configurações:

  1. RegExp avalie : "<% code%>" na cadeia de modelo
  2. RegExp interpola : "<% = code%>" na cadeia de modelo
  3. RegExp escape : "<% - code%>"
  4. Variável de cadeia : opcional, o nome do parâmetro de dados na cadeia de modelo

O código em uma seção de avaliação será simplesmente avaliado. Você pode adicionar string desta seção com o comando __p + = "mystring" ao modelo avaliado, mas isso não é recomendado (não faz parte da interface de modelagem), use a seção interpolar em vez disso. Este tipo de seção é para adicionar blocos como se ou para o modelo.

O resultado do código na seção interpolar será adicionado ao modelo avaliado. Se nulo for devolvido, a sequência vazia será adicionada.

A seção de escape escapa html com _.escape no valor de retorno do código fornecido. Portanto, a sua semelhante do que um _.escape (código) em um interpolate secção, mas escapa com \ os caracteres em branco como \ n antes de passar o código para o _.escape . Não sei por que isso é importante, está no código, mas funciona bem com o interpolar e _.escape - que não escapa aos caracteres do espaço em branco - também.

Por padrão, o parâmetro data é passado por uma instrução with (data) {...} , mas esse tipo de avaliação é muito mais lento que a avaliação com a variável nomeada. Portanto, nomear os dados com o parâmetro variável é algo bom ...

Por exemplo:

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"

Você pode encontrar aqui mais exemplos de como usar o modelo e substituir as configurações padrão: http://underscorejs.org/#template

Ao carregar o modelo, você tem muitas opções, mas no final você sempre precisa converter o modelo em string. Você pode atribuí-la como sequência normal, como no exemplo acima, ou carregá-la a partir de uma tag de script e usar a função .html () do jquery, ou carregá-la de um arquivo separado com o plugin tpl do require.js .

Outra opção para construir a árvore de dom com lacônico em vez de modelagem.


21

Estou dando um exemplo muito simples

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

O resultado seria

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

2) Este é um modelo

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

Este é html

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

Este é o código javascript que contém o objeto json e coloca o modelo em 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}));
  });


14

com express é tão fácil. tudo o que você precisa é usar o módulo consolidar no nó para que você precise instalá-lo:

npm install consolidate --save

você deve alterar o mecanismo padrão para o modelo html da seguinte forma:

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

registre o mecanismo de modelo de sublinhado para a extensão html:

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

está feito !

Agora, para carregar, por exemplo, um modelo chamado 'index.html':

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

talvez você precise instalar o módulo de sublinhado.

npm install underscore --save

Espero que isso tenha ajudado!


12

Eu queria compartilhar mais uma descoberta importante.

o uso de <% = variable => resultaria em vulnerabilidade de script entre sites. Portanto, é mais seguro usar <% - variable ->.

Tivemos que substituir <% = por <% - para evitar ataques de script entre sites. Não tenho certeza, se isso terá algum impacto no desempenho


2
+1 Adicionei uma observação sobre o XSS ao meu exemplo. Esse é um argumento muito bom sobre como injetar informações de usuário não autorizadas em uma página da web. por meio de um mecanismo de modelo ou mesmo $ .html ().
Shanimal

1

Lodash também é o mesmo Primeiro, escreva um script da seguinte maneira:

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

Agora escreva algumas JS simples da seguinte maneira:

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

Onde popoup é uma div em que você deseja gerar a tabela

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.