JavaScriptでHTMLを生成するためのベストプラクティスはありますか


103

JSONでオブジェクトの配列を返すWebサービスを呼び出しています。これらのオブジェクトを取得して、divにHTMLを入力したいと思います。各オブジェクトにURLと名前が含まれているとしましょう。

オブジェクトごとに次のHTMLを生成したい場合:

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

このためのベストプラクティスはありますか?私はそれを行ういくつかの方法を見ることができます:

  1. 文字列を連結する
  2. 要素を作成する
  3. テンプレートプラグインを使用する
  4. サーバー上でhtmlを生成し、JSONを介して提供します。

1
また、アンダースコアjsを確認することもできます:documentcloud.github.com/underscore/#templateこれは、backbone.jsで非常にうまく機能します
luacassus

1から4の選択肢の選択:注入するコンテンツの量によって異なります(大きい場合は4を推奨)合計でいくつのHTMLパーツを追加する必要があるか(3または4)。sbは何に精通しているか。(開発時間への影響)。ツールがわからない場合は、純粋なjsよりも良い方法を知らないと注入される小さなモーダル(1-2)
partizanos

回答:


68

オプション#1と#2は、最も直接的な直接的なオプションになりますが、どちらのオプションでも、文字列を作成するかDOMオブジェクトを作成することにより、パフォーマンスとメンテナンスへの影響を感じます。

テンプレート化はそれほど未成熟ではなく、主要なJavascriptフレームワークのほとんどでポップアップ表示されています。

パフォーマンスへの影響を軽減するJQueryテンプレートプラグインの例を次に示します。これは非常に簡単です。

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

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

私はクールなルート(そしてより良いパフォーマンス、より保守しやすい)に行き、テンプレートを使用すると言います。


13
JQueryテンプレート作成は停止しているようです。stackoverflow.com/ questions / 7911732 /…を参照してください
James McMahon

4
@ジム・フィオラト:リンクは死んでいる:s
Adrien Be

2
エイドリアンが指摘するように、リンクは死んでいる。回答を更新して含めるように
提案

1
誰かがjQueryベースの回答が受け入れられる理由を説明できますか?これがベストプラクティスであるとは思えません。
WoIIe

1
@WoIIeさらに悪いことに、jQueryプラグインは機能していないため、この回答は古くなっています。
フランクリンYu

13

通常の代わりに文字列を絶対に連結する必要がある場合:

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は恐ろしいブラウザーでしたが、良くなっています。しかし、私が元に戻ることはないと思います。
いくつかの

1
最初の方法で見られるパフォーマンスの低下は、結果の文字列を200回再割り当てする必要があり、メモリ割り当てが遅くなる可能性があるためと考えられます。2回の反復の後、「testingtesting」があります。3回の反復の後、その文字列は破棄され、「testingtestingtesting」に十分なスペースのあるメモリが割り当てられます。そして、長さが徐々に増加する200回などです。ただし、s.join()は、結果としてそれらすべてに適合するのに十分な長さの新しい文字列を1つ割り当て、それぞれにコピーします。1つの割り当て、はるかに高速です。
EricP 2014年

1
@JoeCoder、同意、そのShlemiel The Painterアルゴリズム。joelonsoftware.com/articles/fog0000000319.html
Jodrell

8

最初の2つのオプションはどちらも一般的であり、受け入れられます。

Prototypeでそれぞれの例を示します。

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

アプローチ#1:

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

アプローチ#2:

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

DOM要素ではなく文字列を使用して明示的にHTMLを生成するように構築すると、パフォーマンスが向上し(文字列の連結は実際の問題ではないと想定)、読みやすくなります。
Rodrick Chapman、

IEでは、文字列の連結が常に問題になります。代わりに配列を使用してください。
いくつかの

7

おそらくより現代的なアプローチは、javascriptを含む多くの言語で実装されているMustacheなどのテンプレート言語を使用することです。例えば:

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

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

追加のメリットも得られます。同じテンプレートをサーバー側などの他の場所で再利用できます。

より複雑なテンプレート(ifステートメント、ループなど)が必要な場合は、より多くの機能を備え、Mustacheと互換性のあるハンドルバーを使用できます。


6

jQuery用のシンプルテンプレートプラグインを使用した例を次に示します。

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 2017年

4

テンプレート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*/})

3

情報開示:私は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へのデータの挿入をサポートしていません。これはtodolistにあります。現時点では、出力を通常の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


2

このためのベストプラクティスはありますか?私はそれを行ういくつかの方法を見ることができます:

  1. 文字列を連結する
  2. 要素を作成する
  3. テンプレートプラグインを使用する
  4. サーバー上でhtmlを生成し、JSONを介して提供します。

1)これはオプションです。クライアント側でJavaScriptを使用してHTMLを作成し、それを全体としてDOMに挿入します。

このアプローチの背後にはパラダイムがあることに注意してください。サーバーはデータのみを出力し、(対話の場合)AJAXリクエストを使用してクライアントからデータを非同期で受信します。クライアント側のコードは、スタンドアロンのJavaScript Webアプリケーションとして動作します。

Webアプリケーションは、サーバーが起動していなくても、動作し、インターフェースをレンダリングする場合があります(もちろん、データを表示したり、あらゆる種類の対話を提供したりすることはありません)。

このパラダイムは最近採用されることが多く、フレームワーク全体がこのアプローチを中心に構築されています(backbone.jsなどを参照)。

2)パフォーマンス上の理由から、可能な場合は、HTMLを文字列に構築し、それを全体としてページに挿入することをお勧めします。

3)これは別のオプションであり、Webアプリケーションフレームワークを採用しています。他のユーザーが利用可能なさまざまなテンプレートエンジンを投稿しています。あなたはそれらを評価し、この道を進むかどうかを決定するスキルを持っているという印象を持っています。

4)別のオプション。ただし、プレーンテキスト/ htmlとして提供してください。なぜJSONなのか?PHP(サーバー言語)とHtmlが混在しているため、このアプローチは好きではありません。しかし、私はそれをオプション14の間の合理的な妥協としてしばしば採用します。


私の答え:あなたはすでに正しい方向に向かっています。

14の間のアプローチを採用することをお勧めしますます。それ以外の場合は、Webフレームワークまたはテンプレートエンジンを採用します。

私の経験に基づく私の意見...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.