我有一个我正在循环的数组。每次条件成立时,我都想将下面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
});
});
答案 0 :(得分:135)
您可以决定在项目中使用模板引擎,例如:
如果您不想包含其他图书馆,John Resig会提供jQuery solution,类似于下面的图书。
浏览器和屏幕阅读器会忽略无法识别的脚本类型:
<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);
});
答案 1 :(得分:126)
老问题,但由于问题是“使用jQuery”,我想我会提供一个选项,让您可以在不引入任何供应商依赖的情况下执行此操作。
虽然那里有很多模板引擎,但是他们的许多功能最近都不受欢迎,包括迭代(<% for
),条件(<% if
)和变换({{1}在最好的情况下被视为微语言,在最坏的情况下被视为反模式。现代模板实践鼓励简单地将对象映射到其DOM(或其他)表示,例如,我们看到的属性映射到ReactJS中的组件(尤其是无状态组件)。
您可以依赖的一个属性,用于将模板的HTML保留在HTML的其余部分旁边,方法是使用不执行的<%= myString | uppercase %>
<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]
很好地映射它,并使用映射函数:
Array#map
function render(props) {
return function(tok, i) { return (i % 2) ? props[tok] : tok; };
}
看起来像props
。
假设您已经解析并加载了{ url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }
,如上所述,并且您在范围内有itemTpl
数组:
items
这种方法也只是jQuery - 你应该能够采用与$('.search').keyup(function () {
$('.list-items').append(items.map(function (item) {
return itemTpl.map(render(item)).join('');
}));
});
和document.querySelector
一起使用vanilla javascript的相同方法。
要问自己的一个问题是:您真的想要/需要将模板定义为HTML文件吗?您可以像重新使用大多数想要重复的东西一样对组件进行组件化和重新使用模板:使用函数。
在es7-land中,使用解构,模板字符串和箭头函数,您可以编写完全漂亮的组件函数,可以使用上面的.innerHTML
方法轻松加载。
$.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>
`;
哦,最后注意:不要忘记清理传递给模板的属性,如果它们是从数据库中读取的,或者有人可以从您的页面传入HTML(然后运行脚本等)。 / p>
答案 2 :(得分:28)
由于接受的答案将代表重载脚本方法,我想建议另一个,在我看来,由于重载脚本带来的XSS风险,它更清洁,更安全。
我制作了一个demo来向您展示如何在动作中使用它以及如何将一个模板注入另一个模板,编辑然后添加到文档DOM中。
<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>
// 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);
+其含量在激活前有效惰性。基本上,你的 标记是隐藏的DOM,不会呈现。
+模板中的任何内容都不会产生副作用。
+内容被视为不在文档中。在主页面中使用document.getElementById()
或querySelector()
将不会返回模板的子节点。
+模板可以放置在<head>
,<body>
或<frameset>
内的任何位置,并且可以包含这些元素中允许的任何类型的内容。请注意,“任何地方”表示<template>
可以安全地用于HTML解析器不允许的位置。
浏览器支持应该不是问题,但如果您想要涵盖所有可能性,您可以轻松检查:
要检测
<template>
功能,请创建DOM元素并进行检查 .content属性存在:
function supportsTemplate() {
return 'content' in document.createElement('template');
}
if (supportsTemplate()) {
// Good to go!
} else {
// Use old templating techniques or libraries.
}
<script>
标记默认为display:none
。"text/javascript"
以外的其他内容。.innerHTML
。用户提供的数据的运行时字符串解析很容易导致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
答案 3 :(得分:14)
在正文中添加
<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>
然后创建css
.hide { display: none; }
并添加到您的js
$('#output').append( $('.hide').html() );
答案 4 :(得分:3)
其他选择:Pure
我使用它并且它帮助了我很多。 他们网站上显示的一个例子:
<强> HTML 强>
<div class="who">
</div>
<强> JSON 强>
{
"who": "Hello Wrrrld"
}
<强>结果强>
<div class="who">
Hello Wrrrld
</div>
答案 5 :(得分:2)
为了解决这个问题,我认识到两个解决方案:
第一个是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中的任何位置,选择它并将其隐藏在jQuery中:
temp = $('.list_group_item').hide()
您可以使用
添加模板的新实例$('.search').keyup(function() {
$('.list-items').html(null);
$.each(items, function(index) {
$(this).append(temp.clone())
});
});
与前一个相同,但如果您不希望模板保留在那里,但只是在javascript中,我认为您可以使用(尚未测试过它!).detach()
而不是隐藏。
temp = $('.list_group_item').detach()
.detach()
从DOM中删除元素,同时保持数据和事件的活动(.remove()不会!)。
答案 6 :(得分:1)
answer的DevWL很好,关于使用本机HTML5 template元素。
为了对OP中的这个好问题做出贡献,我想补充一下如何使用jQuery使用template
元素,例如:
$($('template').html()).insertAfter( $('#somewhere_else') );
template
的内容不是html,而是被视为数据,因此您需要将内容包装到jQuery对象中,然后才能访问jQuery的方法。
答案 7 :(得分:0)
以下是如何更有效地使用 <template>
元素和 jQuery,因为截至撰写本文时,其他 jQuery 答案使用 .html()
,这会强制对 HTML 进行序列化和重新解析。
首先以模板为例:
<template id="example"><div class="item">
<h1 class="title"></h1>
<p class="description"></p>
</div></template>
请注意,<template>
标记与其内容之间没有空格,内容结尾和 </template>
之间也没有空格。如果你把空间放在那里,它也会被复制。
现在,JS:
// example data
const items = [
{name: "Some item", description: "Some description"},
// ...
];
const template = $("template#example").contents();
const templateTitle = template.find("h1.title");
const templateDescription = template.find("p.description");
const target = $("body");
for (const item of items) {
// fill in the placeholders
templateTitle.text(item.name);
templateDescription.text(item.description);
// copy the template and add it to the page
target.append(template.clone());
}
这将为 items 数组中的每个项目添加模板副本,替换占位符。请注意,多个元素(如 template
和 target
)仅被检索一次。