老问题,但由于问题询问“使用 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]
格式获得它。这让我们可以使用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
在范围内有一个数组:
$('.search').keyup(function () {
$('.list-items').append(items.map(function (item) {
return itemTpl.map(render(item)).join('');
}));
});
这种方法也只是勉强使用 jQuery - 您应该能够使用带有document.querySelector
和 的vanilla javascript 来采用相同的方法.innerHTML
。
提琴手
JS 中的模板
要问自己的一个问题是:您真的想要/需要将模板定义为 HTML 文件吗?您始终可以组件化 + 重用模板,就像重用大多数要重复的东西一样:使用函数。
在 es7-land 中,使用解构、模板字符串和箭头函数,您可以编写非常漂亮的组件函数,这些函数可以使用上述$.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(然后运行脚本等)。