定义一个使用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