定义一个使用JQuery追加的HTML模板

我有一个数组,我正在循环。 每当条件成立时,我想将下面的HTML代码的副本附加到具有一些值的容器元素。

我在哪里可以把这个HTML重新使用一个聪明的方式?

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

您可以决定在您的项目中使用模板引擎,例如:

  • 胡子
  • underscore.js
  • 车把

如果您不想包含其他库,John Resig提供了一个类似于下面的jQuery解决scheme 。


浏览器和屏幕阅读器忽略无法识别的脚本types:

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

使用jQuery,添加基于模板的行将类似于:

 var template = $('#hidden-template').html(); $('button.addRow').click(function() { $('#targetTable').append(template); }); 

老问题,但因为问题问“使用jQuery”,我想我会提供一个选项,让你做到这一点,而不引入任何供应商的依赖。

虽然有很多模板引擎,但是它们的许多特性最近都不受欢​​迎,比如迭代( <% for ),条件( <% if )和变换( <%= myString | uppercase %> )最好是微语言,最糟糕的是反模式。 现代模板实践鼓励简单地将对象映射到其DOM(或其他)表示,例如我们通过映射到ReactJS中的组件(特别是无状态组件)的属性来看到的。

HTML内的模板

您可以依赖的一个属性将HTML保留在HTML其余部分的旁边,方法是使用不执行的<script> type ,例如<script type="text/template"> 。 对于你的情况:

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

在文档加载时,请阅读您的模板并使用简单的String#split对其进行标记

 var itemTpl = $('script[data-template="listitem"]').text().split(/\$\{(.+?)\}/g); 

请注意,使用我们的令牌,您可以交替使用[text, property, text, property]格式。 这可以让我们用映射函数很好地映射它:

 function render(props) { return function(tok, i) { return (i % 2) ? props[tok] : tok; }; } 

props看起来像{ url: 'http://foo.com', img: 'http://img.dovov.combar.png', title: 'Lorem Ipsum' }

把它放在一起假设你已经parsing并加载了你的itemTpl ,如上所示,并且你有一个范围内的items数组:

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

这种方法也只是几乎没有jQuery – 你应该能够采用相同的方法使用香草的JavaScript与document.querySelector.innerHTML

的jsfiddle

JS里面的模板

一个问自己的问题是:你真的想/需要将模板定义为HTML文件吗? 您可以随时使用模板进行组件化和重新使用,就像重用大部分您想要重复的事情一样:使用函数。

在es7-land中,使用解构,模板string和箭头函数,可以使用上面的$.fn.html方法轻松地编写完美的组件函数。

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

然后你可以很容易地渲染它,甚至映射到一个数组,就像这样:

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

哦,最后一点:不要忘记清理传递给模板的属性,如果它们是从数据库中读取的,或者有人可以从页面传递HTML(然后运行脚本等)。

添加在身体的某个地方

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

然后创buildCSS

 .hide { display: none; } 

并添加到您的js

 $('#output').append( $('.hide').html() ); 

其他select: 纯

我用它,它帮了我很多。 在他们的网站上显示一个例子:

HTML

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

JSON

 { "who": "Hello Wrrrld" } 

结果

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

为了解决这个问题,我认识到两个解决scheme:

  • 第一个是AJAX,你需要从另一个文件中加载模板,然后每次使用.clone()

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

    考虑到ajax完成后应该添加事件,以确保数据可用!

  • 第二个将直接添加到原始html中的任何地方,select它并将其隐藏在jQuery中:

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

    您可以在添加模板的新实例之后

     $('.search').keyup(function() { $('.list-items').html(null); $.each(items, function(index) { $(this).append(temp.clone()) }); }); 
  • 和上一个一样,但是如果你不想让模板留在那里,而只是在javascript中,我想你可以使用(没有testing过!). .detach()而不是隐藏。

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

    .detach()从DOM中移除元素,同时保持数据和事件的活动(.remove()不!)。

改用HTML模板!

由于被接受的答案会代表重载脚本方法,所以我想提出另一个scheme,在我看来,由于XSS风险与脚本重载而带来更多更清洁和更安全的方法。

我做了一个演示,向您展示如何在一个动作中使用它,以及如何将一个模板注入到另一个模板中,编辑然后添加到文档DOM中。 https://codepen.io/DevWL/pen/YrjyWm?editors=1010

例如html

 <template id="mytemplate"> <a href="#" class="list-group-item"> <div class="image"> <img src="" /> </div> <p class="list-group-item-text"></p> </a> </template> 

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

  • +它的内容是有效的惰性,直到激活。 本质上,你的标记是隐藏的DOM,并不呈现。

  • +模板中的任何内容都不会有副作用。 脚本不运行,图像不加载,audio不播放,直到使用模板。

  • +内容被认为不在文档中。 在主页面中使用document.getElementById()querySelector()将不会返回模板的子节点。

  • +模板可以放在<head><body>或者<frameset>任何地方,并且可以包含这些元素允许的任何types的内容。 请注意,“任何地方”意味着<template>可以安全地在HTML分析器不允许的地方使用。

倒退

浏览器的支持不应该是一个问题,但如果你想覆盖所有的可能性,你可以做一个简单的检查:

要检测<template> ,请创buildDOM元素并检查.content属性是否存在:

 function supportsTemplate() { return 'content' in document.createElement('template'); } if (supportsTemplate()) { // Good to go! } else { // Use old templating techniques or libraries. } 

关于重载脚本方法的一些见解

  • +不呈现任何内容 – 浏览器不呈现此块,因为<script>标记默认display:none
  • + Inert – 浏览器不会将脚本内容parsing为JS,因为它的types设置为"text/javascript"
  • 安全问题 – 鼓励使用.innerHTML 。 用户提供的数据的运行时stringparsing可能很容易导致XSS漏洞。

全文: https : //www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old

有用的参考: https : //developer.mozilla.org/en-US/docs/Web/API/Document/importNode http://caniuse.com/#feat=queryselector