用JavaScript生成HTML有最佳实践吗?

116

我正在调用一个返回JSON对象数组的Web服务。我想使用这些对象来填充HTML div。假设每个对象包含一个URL和一个名称。

如果我想为每个对象生成以下HTML:

<div><img src="the url" />the name</div>

在这方面有最佳实践吗?我可以看到几种做法:

  1. 连接字符串
  2. 创建元素
  3. 使用模板插件
  4. 在服务器上生成HTML,然后通过JSON提供服务。

1
你也可以查看underscore js:http://documentcloud.github.com/underscore/#template 它与backbone.js非常兼容。 - luacassus
选择mong 1-4:取决于要注入多少内容(更喜欢4用于更大的内容),总共需要附加多少不同的HTML部分(3或4),以及sb熟悉哪些工具(影响开发时间)。如果您不知道任何工具,那么它只是一个小型模态,将被注入一次。我不知道比纯JS更好的方法来做到这一点(1-2)。 - partizanos
HTML 字符串模板 https://www.w3schools.com/js/js_string_templates.asp - Eric
8个回答

68
选项#1和#2是您最直接的选择,但对于这两个选项,无论是构建字符串还是创建DOM对象,您都会感受到性能和维护方面的影响。
模板并不是那么不成熟,在大多数主要的Javascript框架中都可以看到它的出现。
下面是一个在JQuery模板插件中的例子,它将为您节省性能损失,并且非常直观易懂。请参考:JQuery模板插件
var t = $.template('<div><img src="${url}" />${name}</div>');

$(selector).append( t , {
     url: jsonObj.url,
     name: jsonObj.name
});

我建议你选择更酷、性能更好、易于维护的模板化方法。


15
JQuery模板似乎已经停止更新了,详见https://dev59.com/3Wsz5IYBdhLWcg3wbHEw。 - James McMahon
4
@Jim Fiorato:链接已失效 :s - Adriano
2
链接已失效,正如Adrien所指出的那样。建议您更新您的答案,包括:Mustache.js - Mr. Polywhirl
2
有人能解释一下为什么基于jQuery的答案被接受了吗?我怀疑这是否是最佳实践! - ˈvɔlə
1
@WoIIe 更糟糕的是,这个jQuery插件已经停止更新了,所以这个答案已经过时了。 - Franklin Yu
1
10年后,您可以使用纯JS完成此操作,并且它将在任何普通浏览器中工作,使用反引号进行多行字符串和模板文字\<h1>${title}</h1>``。 - JoKr

14
如果您一定要连接字符串,而不是使用正常的 ":",则可以使用以下方法:
var s="";
for (var i=0; i < 200; ++i) {s += "testing"; }

使用临时数组:

var s=[];
for (var i=0; i < 200; ++i) { s.push("testing"); }
s = s.join("");

使用数组速度更快,特别是在IE浏览器中。我之前用IE7、Opera和FF对字符串进行了一些测试。Opera只需0.4秒就能完成测试,但IE7花了20分钟仍未完成测试(不是开玩笑)。使用数组后,IE浏览器的速度非常快。


我很久以前就换了浏览器,所以我不会遭受那么多痛苦。IE是一个可怕的浏览器,但现在变得越来越好了。但我怀疑我永远不会再切换回去了。 - some
1
第一种方法中出现的缓慢性能可能是因为结果字符串必须重新分配200次,而内存分配可能很慢。经过两次迭代,您将获得“testingtesting”。经过三次迭代,该字符串被丢弃,并分配具有足够空间容纳“testingtestingtesting”的内存。如此进行200次,长度逐渐增加。然而,s.join()分配一个新字符串作为结果,其长度足以容纳所有字符串,然后将每个字符串复制到其中。只需一次分配,速度更快。 - EricP
1
@JoeCoder,同意,这是一个Shlemiel The Painter算法。http://www.joelonsoftware.com/articles/fog0000000319.html - Jodrell

9

前两个选项都是常见且可接受的。

我将在Prototype中给出每个选项的示例。

// assuming JSON looks like this:
// { 'src': 'foo/bar.jpg', 'name': 'Lorem ipsum' }

方法一:

var html = "<div><img src='#{src}' /> #{name}</div>".interpolate(json);
$('container').insert(html); // inserts at bottom

方法二:

var div = new Element('div');
div.insert( new Element('img', { src: json.src }) );
div.insert(" " + json.name);
$('container').insert(div); // inserts at bottom

使用字符串显式地构建生成HTML比使用DOM元素更高效(假设字符串连接不是真正的问题),并且更易读。 - Rodrick Chapman
在IE中,字符串拼接总是一个问题。请改用数组。 - some

7
这是一个例子,使用我的jQuery插件Simple Templates

var tmpl = '<div class="#{classname}">#{content}</div>';
var vals = {
    classname : 'my-class',
    content   : 'This is my content.'
};
var html = $.tmpl(tmpl, vals);

1
不错。几个月前我在一个大项目中本可以用到这样的东西。 - Rodrick Chapman
是的。简洁而整洁! - ajitweb

7

也许更现代的方法是使用像 Mustache这样的模板语言,它在许多语言中都有实现,包括JavaScript。例如:

var view = {
  url: "/hello",
  name: function () {
    return 'Jo' + 'hn';
  }
};

var output = Mustache.render('<div><img src="{{url}}" />{{name}}</div>', view);

你甚至可以得到一个额外的好处 - 你可以在其他地方重复使用相同的模板,比如服务器端。
如果你需要更复杂的模板(例如if语句、循环等),你可以使用Handlebars,它具有更多的特性,并且与Mustache兼容。

5
您可以将模板的HTML添加到页面上的隐藏div中,然后使用cloneNode和您喜欢的库的查询功能来填充它。
/* CSS */
.template {display:none;}

<!--HTML-->
<div class="template">
  <div class="container">
    <h1></h1>
    <img src="" alt="" />
  </div>
</div>

/*Javascript (using Prototype)*/
var copy = $$(".template .container")[0].cloneNode(true);
myElement.appendChild(copy);
$(copy).select("h1").each(function(e) {/*do stuff to h1*/})
$(copy).select("img").each(function(e) {/*do stuff to img*/})

4

声明:本人是BOB的维护者。

有一个名为BOB的JavaScript库可以使此过程更加容易。

针对您的具体示例:

<div><img src="the url" />the name</div>

这可以通过以下代码使用BOB生成。
new BOB("div").insert("img",{"src":"the url"}).up().content("the name").toString()
//=> "<div><img src="the url" />the name</div>"

或者使用更短的语法

new BOB("div").i("img",{"src":"the url"}).up().co("the name").s()
//=> "<div><img src="the url" />the name</div>"

这个库非常强大,可以用于创建具有数据插入的非常复杂的结构(类似于d3),例如:

data = [1,2,3,4,5,6,7]
new BOB("div").i("ul#count").do(data).i("li.number").co(BOB.d).up().up().a("a",{"href": "www.google.com"}).s()
//=> "<div><ul id="count"><li class="number">1</li><li class="number">2</li><li class="number">3</li><li class="number">4</li><li class="number">5</li><li class="number">6</li><li class="number">7</li></ul></div><a href="www.google.com"></a>"

目前 BOB 不支持将数据注入到 DOM 中,但这在待办事项中。现在,您可以将输出与普通的 JS 或 jQuery 一起使用,并将其放在任何您想要的位置。

document.getElementById("parent").innerHTML = new BOB("div").insert("img",{"src":"the url"}).up().content("the name").s();
//Or jquery:
$("#parent").append(new BOB("div").insert("img",{"src":"the url"}).up().content("the name").s());

我开发了这个库,因为我不喜欢像jquery和d3这样的替代品。它们的代码非常复杂,很难阅读。在我看来(显然是有偏见的),使用BOB要愉快得多。

BOB可以通过Bower获取,只需运行bower install BOB即可。


你做得很好。:) 尽管我希望在将其应用于复杂情况之前投入时间来理解它的结构。但是,在我看来,这是最好的解决方案。 - Imran Faruqi
1
感谢@ImranFaruqi。我已经有很长一段时间没有使用这个库了,但是它应该按照预期工作。如果你觉得有用的话,请随意帮忙! - Automatico

2
有关这个问题的最佳实践是什么?我能想到几种方法:
1.连接字符串
2.创建元素
3.使用模板插件
4.在服务器上生成html代码,然后通过JSON提供服务。
1) 这是一个选择。在客户端使用JavaScript构建HTML,并将其作为整体注入DOM。请注意,这种方法背后的范例是:服务器只输出数据,并且(如果涉及交互)使用AJAX请求异步从客户端接收数据。客户端代码操作为独立的JavaScript Web应用程序。Web应用程序可以操作、呈现界面,即使服务器关闭(当然不会显示任何数据或提供任何形式的交互)。
2) 为了性能原因,尽可能在字符串中构建HTML然后将其作为整体注入页面。
3) 这是另一种选择,以及采用Web应用程序框架。其他用户已发布了各种可用的模板引擎。我有这样的印象,你有评估它们并决定是否跟随此路径的技能。
4) 另外一个选项。但是把它作为普通的文本/ HTML提供;为什么是JSON?我不喜欢这个方法,因为它混合了PHP(您的服务器语言)和Html。但我经常采用它作为方案1和方案4之间的合理折衷方案。
我的答案:你已经朝着正确的方向寻找。我建议采用类似于我所做的方案1和方案4之间的方法。否则,请采用Web框架或模板引擎。这只是基于我的经验提出的意见。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接