質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • JavaScript

    15972questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • HTML

    8695questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

JavaScriptでDOMを動的に生成する際のスマートな書き方に関して

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,600

elelboo

score 15

前提・実現したいこと

下記HTMLのDOMをJavaScriptで動的に生成したいと考えています。
自分なりに書き、動作は確認できました。
しかし冗長すぎるし、メンテし辛く間違いも起こりそうです。もっと良い書き方があるのではないかと…

スマートな書き方を教えていただきたいです。
再帰的に関数呼び出すことで、解決できるのでしょうか?
よろしくお願いいたします

該当のソースコード

<div>
    <div class="context">
        <a href="http://localhost:3000"></a>
    </div>
    <div class="content">
        <div class="item-header">
            <a href="" class="profile"><span class="name">名前</span></a>
            <small class="time">YYYY-MM-DD</small>
        </div>
        <div class="text-container">
            <p class="comment">コメント内容</p>
        </div>
        <div class="item-fotter">
            <span class="reply"></span>
            <span class="retweet"></span>
        </div>
    </div>
</div>
//仮データ ループが周るかどうかの確認用
var data = [["Jan","Feb","Mar","Apr"],["a", "b", "c", "d"]];
var fragment = document.createDocumentFragment();
for (var i = 0, len = data.length; i < len; i++) {
   var items = data[i].length;
   for (var j = 0; j < items; j++) {
       var div = document.createElement('div');
       var context = document.createElement('div');
       context.classList.add('context');
       var a = document.createElement('a');
       a.setAttribute('href', 'http://localhost:3000');
       context.appendChild(a);
       var content = document.createElement('div');
       content.classList.add('content');
       var content2 = document.createElement('div');
       content2.classList.add('item-header');
       var content3 = document.createElement('a');
       content3.classList.add('profile');
       var content4 = document.createElement('span');
       content4.classList.add('name');
       content4.insertAdjacentHTML('afterbegin','名前');
       var content5 = document.createElement('small');
       content5.classList.add('time');
       content5.insertAdjacentHTML('afterbegin','YYYY-MM-DD');
       content3.appendChild(content4);
       content2.appendChild(content3);
       content2.appendChild(content5);
       //div.content
       content.appendChild(content2);
       var elmc = document.createElement('div');
       elmc.classList.add('text-container');
       var elmc2 = document.createElement('p');
       elmc2.classList.add('comment');
       elmc2.insertAdjacentHTML('afterbegin','コメント内容');
       //div.text-container
       elmc.appendChild(elmc2);
       var elmf = document.createElement('div');
       elmf.classList.add('item-fotter');
       var elmf2 = document.createElement('span');
       elmf2.classList.add('reply');
       var elmf3 = document.createElement('span');
       elmf3.classList.add('retweet');
       //div.item-fotter
       elmf.appendChild(elmf2);
       elmf.appendChild(elmf3);
       //div       
       content.appendChild(elmc);
       content.appendChild(elmf);
       div.appendChild(context);
       div.appendChild(content);
       fragment.appendChild(div);
   }
}

■2017/10/02 1:55
「仮データ」とHTMLの関係性が分からなかったため、コードを修正しました。

var data = [["URLA","名前A","日付A","コメントA"],["URLB","名前B","日付B","コメントB"],["URLC","名前C","日付C","コメントC"]]; 

var fragment = document.createDocumentFragment();

for (var i = 0, len = data.length; i < len; i++) {

        var div = document.createElement('div');

        var context = document.createElement('div');
        context.classList.add('context');

        var a = document.createElement('a');
        a.setAttribute('href', data[i][0]);
        context.appendChild(a);

        var content = document.createElement('div');
        content.classList.add('content');

        var content2 = document.createElement('div');
        content2.classList.add('item-header');

        var content3 = document.createElement('a');
        content3.classList.add('profile');

        var content4 = document.createElement('span');
        content4.classList.add('name');
        content4.insertAdjacentHTML('afterbegin',data[i][1]);

        var content5 = document.createElement('small');
        content5.classList.add('time');
        content5.insertAdjacentHTML('afterbegin',data[i][2]);

        content3.appendChild(content4);

        content2.appendChild(content3);
        content2.appendChild(content5);
        //div.content
        content.appendChild(content2);


        var elmc = document.createElement('div');
        elmc.classList.add('text-container');
        var elmc2 = document.createElement('p');
        elmc2.classList.add('comment');
        elmc2.insertAdjacentHTML('afterbegin',data[i][3]);
        //div.text-container
        elmc.appendChild(elmc2);

        var elmf = document.createElement('div');
        elmf.classList.add('item-fotter');
        var elmf2 = document.createElement('span');
        elmf2.classList.add('reply');
        var elmf3 = document.createElement('span');
        elmf3.classList.add('retweet');
        //div.item-fotter
        elmf.appendChild(elmf2);
        elmf.appendChild(elmf3);

        //div        
        content.appendChild(elmc);
        content.appendChild(elmf);

        div.appendChild(context);
        div.appendChild(content);
        fragment.appendChild(div);
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kei344

    2017/10/02 01:47

    回答が付いた質問の編集は慎重に行ってください。質問文のコードについて回答にて指摘があった場合は「追記」し、元のコードを編集する場合も「直したこと」がわかるようにしてください。

    キャンセル

  • elelboo

    2017/10/02 02:02

    配慮が足らずスミマセン。編集画面左下の変更点の要約に入力することで大丈夫だと思っていました。他の質問ページを参考に修正しました。

    キャンセル

  • kei344

    2017/10/02 02:05

    編集履歴は teratail慣れしている回答者は見ますが、検索してたどり着いたユーザーは存在自体に気づかないことが多いのです。編集ありがとうございました。

    キャンセル

回答 3

checkベストアンサー

+2

テンプレート機能はlodash.js(underscore.js)にもありますが、ここは本物のtemplate 要素を使うのがいいでしょう。
https://developer.mozilla.org/ja/docs/Web/HTML/Element/template

IE で動かないことを懸念するかもしれませんが、polyfill もあります。
https://github.com/webcomponents/template

サンプルを提示したいのですが、余裕がないかもしれませんのでここをご覧ください。
https://www.html5rocks.com/ja/tutorials/webcomponents/template/

-- 10/4 追記 サンプル

<template id="hoge">
    <div>
        <div class="context">
            <a href="http://localhost:3000"></a>
        </div>
        <div class="content">
            <div class="item-header">
                <a class="profile"><span class="name">名前</span></a>
                <small class="time">YYYY-MM-DD</small>
            </div>
            <div class="text-container">
                <p class="comment">コメント内容</p>
            </div>
            <div class="item-fotter">
                <span class="reply"></span>
                <span class="retweet"></span>
            </div>
        </div>
    </div>
</template>
<!-- polyfill -->
<script src="template.js"></script>
document.addEventListener('DOMContentLoaded', function(event) {
  var data = [["URLA","名前A","日付A","コメントA"],["URLB","名前B","日付B","コメントB"],["URLC","名前C","日付C","コメントC"]];

  var fragment = document.createDocumentFragment();
  var content = document.getElementById('hoge').content;

  for (var i = 0, len = data.length; i < len; i++) {
    var clone = content.cloneNode(true);
    clone.querySelector('.context a').href = data[i][0];
    clone.querySelector('.name').textContent = data[i][1];
    clone.querySelector('.time').textContent = data[i][2];
    clone.querySelector('.comment').textContent = data[i][3];
    fragment.appendChild(clone);
  }

  document.body.appendChild(fragment);
});

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

ここまでくるとテンプレートエンジンを使いたくなりますね。
pure js でやりたいならこの回答はスルーしてください。

たとえばmustache.jsというライブラリを使うとこうできます。
DEMO

<script id="template" type="x-tmpl-mustache">
{{#items}}
<div>
    <div class="context">
        <a href="{{url}}">link</a>
    </div>
    <div class="content">
        <div class="item-header">
            <a href="" class="profile"><span class="name">{{name}}</span></a>
            <small class="time">{{date}}</small>
        </div>
        <div class="text-container">
            <p class="comment">{{comment}}</p>
        </div>
        <div class="item-fotter">
            <span class="reply"></span>
            <span class="retweet"></span>
        </div>
    </div>
</div>
{{/items}}
</script>

<div id="target">Loading...</div>
const data = {
  items: [
    {url: "111.jp", name: "name1", date: "date1", comment: "comment1"},
    {url: "222.jp", name: "name2", date: "date2", comment: "comment2"},
  ]
}

const template = document.getElementById('template').innerHTML
const rendered = Mustache.render(template, data)
document.getElementById('target').innerHTML = rendered

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

雑ですが。
「仮データ」とHTMLの関係性がわからなかったので、フラットにしてそれぞれをテンプレートに突っ込みました。

let a = `<div>
    <div class="context">
        <a href="http://localhost:3000"></a>
    </div>
    <div class="content">
        <div class="item-header">
            <a href="" class="profile"><span class="name">名前</span></a>
            <small class="time">YYYY-MM-DD</small>
        </div>
        <div class="text-container">
            <p class="comment">コメント内容</p>
        </div>
        <div class="item-fotter">
            <span class="reply"></span>
            <span class="retweet"></span>
        </div>
    </div>
</div>`, b = "", data2;
var data = [["Jan","Feb","Mar","Apr"],["a", "b", "c", "d"]];
data2 = data.reduce( ( pre, curr )=> {
    pre.push.apply( pre, curr );
    return pre;
}, [] );
data2.forEach( curr => {
    b += a.replace( '名前', curr );
} );
document.body.insertAdjacentHTML("beforeend", b );

動くサンプル:https://jsfiddle.net/3khdk7k9/1/


【Array.prototype.reduce() - JavaScript | MDN】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

【Array.prototype.forEach() - JavaScript | MDN】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

【配列の連結(concat vs Array.prototype.push.apply) - Qiita】
https://qiita.com/kaz2ngt/items/6e08acc537fd77273cff

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/02 01:52

    ありがとうございます。ドキュメントと合わせて、理解したいと思います。
    >「仮データ」とHTMLの関係性がわからなかったので
    そうですよね。失礼しました。関係性が分かるように質問を追記・修正しました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    15972questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • HTML

    8695questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。