Definir um modelo HTML a adicionar com o JQuery

Tenho uma matriz que estou a analisar. Cada vez que uma condição é verdadeira, eu quero adicionar uma cópia do código HTML abaixo a um elemento container com alguns valores.

Onde posso colocar este HTML para reutilizar de uma forma inteligente?

<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
    });
});
Author: Patrick Reck, 2013-09-07

6 answers

Você poderia decidir fazer uso de um motor templating em seu projeto, tais como:

Se você não quiser incluir outra Biblioteca, John Resig oferece uma solução jQuery, semelhante à abaixo.


Navegadores e leitores de ecrã ignoram tipos de programas não reconhecidos:

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

Usando o jQuery, adicionar linhas com base no modelo iria assemelhar-se a:

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

$('button.addRow').click(function() {
    $('#targetTable').append(template);
});
 114
Author: Mathijs Flietstra, 2015-02-16 23:05:41

(ou outra) representação, por exemplo, o que vemos com propriedades mapeadas a componentes em ReactJS (especialmente componentes apátridas).

Modelos dentro do HTML

Uma propriedade em que pode confiar para manter o HTML do seu modelo ao lado do resto do seu HTML, é usando um não-execução <script> type, por exemplo <script type="text/template"> Para o seu caso:

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

Na carga do documento, Leia o seu modelo e faça um tokenize com um simples String#split

var itemTpl = $('script[data-template="listitem"]').text().split(/\$\{(.+?)\}/g);
Reparem que com o nosso símbolo, vocês ficam com ele. no formato alternado [text, property, text, property]. Isto permite-nos mapeá-lo bem usando um Array#map, com uma função de mapeamento:
function render(props) {
  return function(tok, i) { return (i % 2) ? props[tok] : tok; };
}

Onde props poderia parecer { url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }.

Juntando tudo, assumindo que analisaste e carregaste o teu {[17] } como acima, e que tens uma matriz items no âmbito:

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

Esta abordagem também é apenas jQuery-você deve ser capaz de tomar a mesma abordagem usando vanilla javascript com document.querySelector e .innerHTML.

Jsfiddle

Modelos no interior do JS

Uma pergunta a fazer a si mesmo é: você realmente quer/precisa definir modelos como arquivos HTML? Você pode sempre componentizar + reutilizar um modelo da mesma forma que reutilizaria a maioria das coisas que deseja repetir: com uma função.

No es7-land, usando as funções de destruição, de template strings e de arrow, você pode escrever funções de componentes bem parecidas que podem ser facilmente carregadas usando o método $.fn.html acima.

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

Então você poderia facilmente rendê-lo, mesmo mapeado a partir de uma matriz, assim:

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

Oh e nota final: não se esqueça de sanitar as suas propriedades passadas para um modelo, se forem lidas de um DB, ou alguém pode passar em HTML (e então executar scripts, etc.) da sua página.

 101
Author: Josh from Qaribou, 2017-07-03 14:05:00

Em vez disso, Use o modelo HTML!

Uma vez que a resposta aceite representaria um método de sobrecarga de script, gostaria de sugerir outro que, na minha opinião, é muito mais limpo e seguro devido aos riscos do XSS que vêm com scripts de sobrecarga.

Fiz uma demonstração para lhe mostrar como usá-la numa acção e como injectar um modelo noutro, Editar e depois adicionar ao DOM do documento.

Exemplo 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>
Exemplo 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 & lttemplate&gt

  • +seu conteúdo é efetivamente inerte até ativado. Essencialmente, o seu a formatação é dom escondido e não renderiza.

  • +qualquer conteúdo dentro de um modelo não terá efeitos colaterais. Os Scripts não correm, as imagens não carregam, o áudio não toca ...até que o modelo seja usado.

  • +o conteúdo não é considerado no documento. A utilização de document.getElementById() ou querySelector() na página principal não devolve os nós-filhos de um modelo.

  • +Os modelos podem ser colocados em qualquer parte do <head>, <body>, ou <frameset> e pode conter qualquer tipo de conteúdo que seja permitido nesses elementos. Note que "em qualquer lugar" significa que <template> pode ser usado com segurança em locais que o analisador HTML não permite.

Recuar

O Suporte do navegador não deve ser um problema, mas se quiser cobrir todas as possibilidades, pode fazer uma verificação fácil:

Para detectar <template>, crie o DOM elemento e verificar que o .a propriedade do conteúdo existe:

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

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

Algumas ideias sobre o método de sobrecarga do script

  • +nada é renderizado-o navegador não renderiza este bloco porque a marca <script> tem display:none por omissão.
  • +inerte - o navegador não analisa o conteúdo do programa como JS porque o seu tipo está definido para algo diferente de "text/javascript".
  • -questões de segurança-encoraja a utilização de .innerHTML. O processamento de texto Em tempo de execução dos dados fornecidos pelo utilizador pode facilmente leva a vulnerabilidades XSS.

Artigo completo: https://www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old

Referência útil: https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode http://caniuse.com/#feat=queryselector

 17
Author: DevWL, 2018-01-08 19:36:56

Adicione algum lugar no corpo

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

Depois criar css

.hide { display: none; }

E adicione ao seu js

$('#output').append( $('.hide').html() );
 15
Author: Mateusz Nowak, 2013-09-07 13:40:08

Outra alternativa: puro

Uso-o e ajudou-me muito. Um exemplo mostrado em seu site:

HTML

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

JSON

{
  "who": "Hello Wrrrld"
}

Resultado

<div class="who">
  Hello Wrrrld
</div>
 3
Author: alditis, 2015-09-20 16:43:21
Para resolver este problema, reconheço duas soluções:
  • O primeiro Vai com AJAX, com o qual você terá que carregar o modelo de outro arquivo e apenas adicionar cada vez que você quiser com .clone().

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

    Tenha em conta que o evento deve ser adicionado uma vez que o ajax tenha completado para ter certeza de que os dados estão disponíveis!

  • O segundo seria adicioná-lo directamente em qualquer ponto do html original, seleccioná-lo e escondê-lo em jQuery:

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

    Poderá depois adicionar uma nova instância do modelo com

    $('.search').keyup(function() {
        $('.list-items').html(null);
    
        $.each(items, function(index) {
            $(this).append(temp.clone())
        });
    });
    
  • O mesmo que o anterior, mas se você não quer que o modelo permaneça lá, mas apenas no javascript, eu acho que você pode usar (não testei!) .detach() em vez de te esconderes.

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

    .detach() remove elementos do DOM mantendo os dados e eventos vivos (.remove () does not!).

 2
Author: Sikian, 2013-09-07 13:56:03