使用 JQuery 定义要附加的 HTML 模板

我得到了一个循环遍历的数组。每当条件为 true 时,我想将下面的 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
});
});
240570 次浏览

在身体某处添加

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

为了解决这个问题,我认为有两种解决办法:

  • 第一个与 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())
    });
    });
    
  • Same as the previous one, but if you don't want the template to remain there, but just in the javascript, I think you can use (have not tested it!) .detach() instead of hide.

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

    .detach()从 DOM 中删除元素,同时保持数据和事件处于活动状态(。

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

如果您不想包含另一个库,JohnResig 提供了一个 JQuery 解决方案,类似于下面的一个。


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

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

其他选择: 纯的

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

超文本标示语言

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

JSON

{
"who": "Hello Wrrrld"
}

结果

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

这是个老问题了,但是因为这个问题问的是“使用 jQuery”,所以我想我应该提供一个选项,让您可以在不引入任何供应商依赖性的情况下完成这项工作。

尽管有很多模板引擎,但它们的很多特性最近都不受欢迎,迭代(<% for)、条件句(<% if)和转换(<%= myString | uppercase %>)充其量被视为微语言,最糟糕的则被视为反模式。现代模板实践鼓励简单地将对象映射到它的 DOM (或其他)表示,例如,我们在 ReactJS 中看到的映射到组件的属性(特别是无状态组件)。

HTML 中的模板

可以依赖的一个属性是使用不执行的 <script> type,例如 <script type="text/template">,将模板的 HTML 与 HTML 的其余部分放在一起。对于你的情况:

<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.innerHTML的普通 javascript 采用相同的方法。

Jsfiddle

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 (然后运行脚本等)。

使用 HTML 模板代替!

由于接受的答案将代表重载脚本方法,我想建议另一种方法,在我看来,由于 XSS 风险随重载脚本而来,这种方法更加干净和安全。

我制作了一个 小样来向您展示如何在操作中使用它,以及如何将一个模板注入另一个模板,编辑并添加到文档 DOM 中。

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

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

  • 他的内容在激活之前是有效的惰性的,基本上你的 标记是隐藏的 DOM,不会呈现

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

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

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

撤退

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

要检测 <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
  • + Inert-浏览器不会将脚本内容解析为 JS,因为它的类型被设置为 "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

创建网页组件 使用 HTML 模板创建自定义网页组件教程 Trawersy Media: Https://youtu.be/pcwafly3vuo

非常好的 回答DevWL关于使用本地 HTML5模板元素。 为了回答 OP 提出的这个好问题,我想补充一下如何使用 jQuery 来使用这个 template元素,例如:

$($('template').html()).insertAfter( $('#somewhere_else') );

template的内容不是 html,而只是作为数据处理,因此需要将内容封装到一个 jQuery 对象中,然后访问 jQuery 的方法。

下面介绍如何更有效地使用 <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());
}

这将为项数组中的每个项添加一个模板副本,并替换占位符。注意,有几个元素,如 templatetarget,只检索一次。