ChatGPT解决这个技术问题 Extra ChatGPT

Is there a best practice for generating html with javascript

I'm calling a web service that returns an array of objects in JSON. I want to take those objects and populate a div with HTML. Let's say each object contains a url and a name.

If I wanted to generate the following HTML for each object:

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

Is there a best practice for this? I can see a few ways of doing it:

Concatenate strings Create elements Use a templating plugin Generate the html on the server, then serve up via JSON.

You could also check underscore js: documentcloud.github.com/underscore/#template It plays very nicely with backbone.js
The choice mong 1-4: depends in how much content is to be injected.(prefer 4 for bigger) how many different html parts will need to be appended in total (3 or 4). what sb is familiar with. (Influence in dev time). If u dont know any tools its just a small modal that will be injected once I dont know amy better way than pure js to do it (1-2)

C
Chris

Options #1 and #2 are going to be your most immediate straight forward options, however, for both options, you're going to feel the performance and maintenance impact by either building strings or creating DOM objects.

Templating isn't all that immature, and you're seeing it popup in most of the major Javascript frameworks.

Here's an example in JQuery Template Plugin that will save you the performance hit, and is really, really straightforward:

var t = $.template('<div><img src="${url}" />${name}</div>');

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

I say go the cool route (and better performing, more maintainable), and use templating.


JQuery templating appears to be dead, see stackoverflow.com/questions/7911732/…
@Jim Fiorato: the link is dead :s
Link is dead, as Adrien points out. Suggest you update your answer to include: Mustache.js
Can someone please explain, why an jQuery-based answer is the accepted one? I doubt that this is best practice!
@WoIIe Even worse, the jQuery plugin is dead, so this answer is outdated.
s
some

If you absolutely have to concatenate strings, instead of the normal :

var s="";
for (var i=0; i < 200; ++i) {s += "testing"; }

use a temporary array:

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

Using arrays is much faster, especially in IE. I did some testing with strings a while ago with IE7, Opera and FF. Opera took only 0.4s to perform the test, but IE7 hadn't finished after 20 MINUTES !!!! ( No, I am not kidding. ) With array IE was very fast.


I switched browser a long time ago, so I don't suffer that much. IE was a horrible browser but it is getting better. But I doubt I will ever switch back.
The slow performance seen in the first method is likely because the result string must be reallocated 200 times, and memory allocations can be slow. After two iterations you have "testingtesting". After three iterations, that string is thrown away and memory with enough room for "testingtestingtesting" is allocated. And so on 200 times with gradually increasing length. However s.join() allocates one new string as a result that's long enough to fit all of them, then copies in each one. One allocation, much faster.
@JoeCoder, agreed, its a Shlemiel The Painter algorithm. joelonsoftware.com/articles/fog0000000319.html
s
savetheclocktower

Either of the first two options is both common and acceptable.

I'll give examples of each one in Prototype.

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

Approach #1:

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

Approach #2:

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

Building generating the HTML explicitly with strings rather than DOM elements is more performant (assuming string concatenation isn't a real issue) and readable.
In IE string concatenation always is an issue. Use an array instead.
A
Andrew Hedges

Here's an example, using my Simple Templates plug-in for jQuery:

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

Neat. I could have used something that like on a big project a few months ago.
Yes. Concise and neat !
T
Tzach

Perhaps a more modern approach is to use a templating language such as Mustache, which has implementations in many languages, including javascript. For example:

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

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

You even get an added benefit - you can reuse the same templates in other places, such as the server side.

If you need more complicated templates (if statements, loops, etc.), you can use Handlebars which has more features, and is compatible with Mustache.


L
Leo

You could add the template HTML to your page in a hidden div and then use cloneNode and your favorite library's querying facilities to populate it

/* 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*/})

C
Community

Disclosure: I am the maintainer of BOB.

There is a javascript library that makes this process a lot easier called BOB.

For your specific example:

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

This can be generated with BOB by the following code.

new BOB("div").insert("img",{"src":"the url"}).up().content("the name").toString()
//=> "<div><img src="the url" />the name</div>"

Or with the shorter syntax

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

This library is quite powerful and can be used to create very complex structures with data insertion (similar to d3), eg.:

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 does currently not support injecting the data into the DOM. This is on the todolist. For now you can simply use the output together with normal JS, or jQuery, and put it wherever you want.

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

I made this library because I was not pleased with any of the alternatives like jquery and d3. The code very complicated and hard to read. Working with BOB is in my opinion, which is obviously biased, a lot more pleasant.

BOB is available on Bower, so you can get it by running bower install BOB.


You did a great job. :) Although I expect to invest time in understanding it's structure before applying in a complex scenario. But, it is the best solution in my opinion.
Thanks @ImranFaruqi There has been a significant amount of time since I worked on the lib, but it should work as expected. Feel free to help out with it if it is useful for you!
P
Paolo

Is there a best practice for this? I can see a few ways of doing it: Concatenate strings Create elements Use a templating plugin Generate the html on the server, then serve up via JSON.

1) This is an option. Build up the html with JavaScript on the client side and then inject it in the DOM as a whole.

Note that there is a paradigm behind this approach: the server outputs just data and (in case of interaction) receives data from the client asyncronoulsy with AJAX requests. The client side code operete as a stand-alone JavaScript web application.

The web application may operate, render the interface, even without the server being up (of course it won't display any data or offer any kind of interaction).

This paradigm is getting adopted often lately, and entire frameworks are build around this approach (see backbone.js for example).

2) For performance reasons, when possible, is better to build the html in a string and then inject it as a whole into the page.

3) This is another option, as well as adopting a Web Application framework. Other users have posted various templating engines available. I have the impression that you have the skills to evaluate them and decide whether to follow this path or not.

4) Another option. But serve it up as a plain text/html; why JSON? I don't like this approach because mixes PHP (your server language) with Html. But I adopt it often as a reasonable compromise between option 1 and 4.

My answer: you are already looking in the right direction.

I suggest to adopt an approach between 1 and 4 like I do. Otherwise adopt a web framework or templating engine.

Just my opinion based on my experience...