使用 JQuery 定义要附加的 HTML 模板
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18673860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Defining a HTML template to append using JQuery
提问by Patrick Reck
I have got an array which I am looping through. Every time a condition is true, I want to append a copy of the HTML
code below to a container element with some values.
我有一个我正在循环的数组。每次条件为真时,我都想将HTML
以下代码的副本附加到具有某些值的容器元素中。
Where can I put this HTML to re-use in a smart way?
我可以把这个 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
});
});
回答by Josh from Qaribou
Old question, but since the question asks "using jQuery", I thought I'd provide an option that lets you do this without introducing any vendor dependency.
老问题,但由于问题询问“使用 jQuery”,我想我会提供一个选项,让您可以在不引入任何供应商依赖性的情况下执行此操作。
While there are a lot of templating engines out there, many of their features have fallen in to disfavour recently, with iteration (<% for
), conditionals (<% if
) and transforms (<%= myString | uppercase %>
) seen as microlanguage at best, and anti-patterns at worst. Modern templating practices encourage simply mapping an object to its DOM (or other) representation, e.g. what we see with properties mapped to components in ReactJS (especially stateless components).
虽然有很多模板引擎,但它们的许多功能最近都不太受欢迎,迭代 ( <% for
)、条件 ( <% if
) 和转换 ( <%= myString | uppercase %>
) 充其量被视为微语言,而最糟糕的是反模式。现代模板实践鼓励简单地将对象映射到它的 DOM(或其他)表示,例如我们看到的映射到 ReactJS 组件(尤其是无状态组件)的属性。
Templates Inside HTML
HTML 中的模板
One property you can rely on for keeping the HTML for your template next to the rest of your HTML, is by using a non-executing <script>
type
, e.g. <script type="text/template">
. For your case:
将模板的 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>
On document load, read your template and tokenize it using a simple String#split
在文档加载时,阅读您的模板并使用简单的标记化 String#split
var itemTpl = $('script[data-template="listitem"]').text().split(/$\{(.+?)\}/g);
Notice that with our token, you get it in the alternating [text, property, text, property]
format. This lets us nicely map it using an Array#map
, with a mapping function:
请注意,使用我们的令牌,您以交替[text, property, text, property]
格式获得它。这让我们可以使用Array#map
, 和映射函数很好地映射它:
function render(props) {
return function(tok, i) { return (i % 2) ? props[tok] : tok; };
}
Where props
could look like { url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }
.
哪里props
会像{ url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }
。
Putting it all together assuming you've parsed and loaded your itemTpl
as above, and you have an items
array in-scope:
假设您已经itemTpl
按照上述方式解析并加载了所有内容,并且您items
在范围内有一个数组:
$('.search').keyup(function () {
$('.list-items').append(items.map(function (item) {
return itemTpl.map(render(item)).join('');
}));
});
This approach is also only just barely jQuery - you should be able to take the same approach using vanilla javascript with document.querySelector
and .innerHTML
.
这种方法也只是勉强使用 jQuery - 您应该能够使用带有document.querySelector
和 的vanilla javascript 来采用相同的方法.innerHTML
。
Templates inside JS
JS 中的模板
A question to ask yourself is: do you really want/need to define templates as HTML files? You can always componentize + re-use a template the same way you'd re-use most things you want to repeat: with a function.
要问自己的一个问题是:您真的想要/需要将模板定义为 HTML 文件吗?您始终可以像重用大多数要重复的东西一样,对模板进行组件化 + 重用:使用函数。
In es7-land, using destructuring, template strings, and arrow-functions, you can write downright pretty looking component functions that can be easily loaded using the $.fn.html
method above.
在 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>
`;
Then you could easily render it, even mapped from an array, like so:
然后你可以轻松地渲染它,甚至从一个数组映射,像这样:
$('.list-items').html([
{ url: '/foo', img: 'foo.png', title: 'Foo item' },
{ url: '/bar', img: 'bar.png', title: 'Bar item' },
].map(Item).join(''));
Oh and final note: don't forget to sanitize your properties passed to a template, if they're read from a DB, or someone could pass in HTML (and then run scripts, etc.) from your page.
哦还有最后一点:不要忘记清理传递给模板的属性,如果它们是从数据库读取的,或者有人可以从您的页面传入 HTML(然后运行脚本等)。
回答by Mathijs Flietstra
You could decide to make use of a templating engine in your project, such as:
您可以决定在您的项目中使用模板引擎,例如:
If you don't want to include another library, John Resig offers a jQuery solution, similar to the one below.
如果您不想包含另一个库,John Resig 提供了一个jQuery 解决方案,类似于下面的解决方案。
Browsers and screen readers ignore unrecognized script types:
浏览器和屏幕阅读器会忽略无法识别的脚本类型:
<script id="hidden-template" type="text/x-custom-template">
<tr>
<td>Foo</td>
<td>Bar</td>
<tr>
</script>
Using jQuery, adding rows based on the template would resemble:
使用 jQuery,基于模板添加行将类似于:
var template = $('#hidden-template').html();
$('button.addRow').click(function() {
$('#targetTable').append(template);
});
回答by DevWL
Use HTML template instead!
请改用 HTML 模板!
Since the accepted answer would represent overloading script method, I would like to suggest another which is, in my opinion, much cleaner and more secure due to XSS risks which come with overloading scripts.
由于接受的答案将代表重载脚本方法,我想建议另一种方法,在我看来,由于重载脚本带来的 XSS 风险,它更干净、更安全。
I made a demoto show you how to use it in an action and how to inject one template into another, edit and then add to the document DOM.
我做了一个演示来向你展示如何在一个动作中使用它,以及如何将一个模板注入另一个模板,编辑然后添加到文档 DOM。
example html
示例 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>
example js
例子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 <template>
HTML <模板>
+Its content is effectively inert until activated. Essentially, your markup is hidden DOM and does not render.
+Any content within a template won't have side effects. Scripts don't run, images don't load, audio doesn't play ...until the template is used.
+Content is considered not to be in the document. Using
document.getElementById()
orquerySelector()
in the main page won't return child nodes of a template.+Templates can be placed anywhere inside of
<head>
,<body>
, or<frameset>
and can contain any type of content which is allowed in those elements. Note that "anywhere" means that<template>
can safely be used in places that the HTML parser disallows.
+它的内容在被激活之前实际上是惰性的。本质上,您的标记是隐藏的 DOM,不会呈现。
+模板中的任何内容都不会产生副作用。脚本不运行,图像不加载,音频不播放......直到使用模板。
+内容被视为不在文档中。在主页中使用
document.getElementById()
或querySelector()
不会返回模板的子节点。+模板可以在任何地方内的放置
<head>
,<body>
或<frameset>
与可以包含任何类型的被允许在这些元素的含量。请注意,“任何地方”意味着<template>
可以安全地用于 HTML 解析器不允许的地方。
Fall back
倒退
Browser support should not be an issue but if you want to cover all possibilities you can make an easy check:
浏览器支持应该不是问题,但如果您想涵盖所有可能性,您可以轻松检查:
To feature detect
<template>
, create the DOM element and check that the .content property exists:
要功能检测
<template>
,请创建 DOM 元素并检查 .content 属性是否存在:
function supportsTemplate() {
return 'content' in document.createElement('template');
}
if (supportsTemplate()) {
// Good to go!
} else {
// Use old templating techniques or libraries.
}
Some insights about Overloading script method
关于重载脚本方法的一些见解
- +Nothing is rendered - the browser doesn't render this block because the
<script>
tag hasdisplay:none
by default. - +Inert - the browser doesn't parse the script content as JS because its type is set to something other than
"text/javascript"
. - -Security issues - encourages the use of
.innerHTML
. Run-time string parsing of user-supplied data can easily lead to XSS vulnerabilities.
- +没有渲染 - 浏览器不渲染这个块,因为
<script>
标签display:none
默认有。 - +Inert - 浏览器不会将脚本内容解析为 JS,因为它的类型设置为
"text/javascript"
. - - 安全问题 - 鼓励使用
.innerHTML
. 用户提供的数据的运行时字符串解析很容易导致 XSS 漏洞。
Full article: https://www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old
全文:https: //www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old
Useful reference: https://developer.mozilla.org/en-US/docs/Web/API/Document/importNodehttp://caniuse.com/#feat=queryselector
有用的参考:https: //developer.mozilla.org/en-US/docs/Web/API/Document/importNode http://caniuse.com/#feat=queryselector
CREATING WEB COMPONENTSCreating custom web components tutorial using HTML templates by Trawersy Media: https://youtu.be/PCWaFLy3VUo
创建 Web 组件Trawersy Media 使用 HTML 模板创建自定义 Web 组件教程:https://youtu.be/PCWaFLy3VUo
回答by Mateusz Nowak
Add somewhere in body
在正文中添加某处
<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>
then create css
然后创建css
.hide { display: none; }
and add to your js
并添加到您的 js
$('#output').append( $('.hide').html() );
回答by alditis
回答by Sebastian Neira
In order to solve this problem, I recognize two solutions:
为了解决这个问题,我认识到两种解决方案:
The first one goes with AJAX, with which you'll have to load the template from another file and just add everytime you want with
.clone()
.$.get('url/to/template', function(data) { temp = data $('.search').keyup(function() { $('.list-items').html(null); $.each(items, function(index) { $(this).append(temp.clone()) }); }); });
Take into account that the event should be added once the ajax has completed to be sure the data is available!
The second one would be to directly add it anywhere in the original html, select it and hide it in jQuery:
temp = $('.list_group_item').hide()
You can after add a new instance of the template with
$('.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()
removes elements from the DOM while keeping the data and events alive (.remove() does not!).
第一个与 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() 没有!)。