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

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

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

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

HTML

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

Q&A

解決済

3回答

8244閲覧

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

elelboo

総合スコア28

JavaScript

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

HTML

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

0グッド

0クリップ

投稿2017/10/01 15:54

編集2017/10/01 16:56

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

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

###該当のソースコード

html

1<div> 2 <div class="context"> 3 <a href="http://localhost:3000"></a> 4 </div> 5 <div class="content"> 6 <div class="item-header"> 7 <a href="" class="profile"><span class="name">名前</span></a> 8 <small class="time">YYYY-MM-DD</small> 9 </div> 10 <div class="text-container"> 11 <p class="comment">コメント内容</p> 12 </div> 13 <div class="item-fotter"> 14 <span class="reply"></span> 15 <span class="retweet"></span> 16 </div> 17 </div> 18</div>

javascript

1//仮データ ループが周るかどうかの確認用 2var data = [["Jan","Feb","Mar","Apr"],["a", "b", "c", "d"]]; 3var fragment = document.createDocumentFragment(); 4for (var i = 0, len = data.length; i < len; i++) { 5 var items = data[i].length; 6 for (var j = 0; j < items; j++) { 7 var div = document.createElement('div'); 8 var context = document.createElement('div'); 9 context.classList.add('context'); 10 var a = document.createElement('a'); 11 a.setAttribute('href', 'http://localhost:3000'); 12 context.appendChild(a); 13 var content = document.createElement('div'); 14 content.classList.add('content'); 15 var content2 = document.createElement('div'); 16 content2.classList.add('item-header'); 17 var content3 = document.createElement('a'); 18 content3.classList.add('profile'); 19 var content4 = document.createElement('span'); 20 content4.classList.add('name'); 21 content4.insertAdjacentHTML('afterbegin','名前'); 22 var content5 = document.createElement('small'); 23 content5.classList.add('time'); 24 content5.insertAdjacentHTML('afterbegin','YYYY-MM-DD'); 25 content3.appendChild(content4); 26 content2.appendChild(content3); 27 content2.appendChild(content5); 28 //div.content 29 content.appendChild(content2); 30 var elmc = document.createElement('div'); 31 elmc.classList.add('text-container'); 32 var elmc2 = document.createElement('p'); 33 elmc2.classList.add('comment'); 34 elmc2.insertAdjacentHTML('afterbegin','コメント内容'); 35 //div.text-container 36 elmc.appendChild(elmc2); 37 var elmf = document.createElement('div'); 38 elmf.classList.add('item-fotter'); 39 var elmf2 = document.createElement('span'); 40 elmf2.classList.add('reply'); 41 var elmf3 = document.createElement('span'); 42 elmf3.classList.add('retweet'); 43 //div.item-fotter 44 elmf.appendChild(elmf2); 45 elmf.appendChild(elmf3); 46 //div 47 content.appendChild(elmc); 48 content.appendChild(elmf); 49 div.appendChild(context); 50 div.appendChild(content); 51 fragment.appendChild(div); 52 } 53}

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

javascript

1 2var data = [["URLA","名前A","日付A","コメントA"],["URLB","名前B","日付B","コメントB"],["URLC","名前C","日付C","コメントC"]]; 3 4var fragment = document.createDocumentFragment(); 5 6for (var i = 0, len = data.length; i < len; i++) { 7 8 var div = document.createElement('div'); 9 10 var context = document.createElement('div'); 11 context.classList.add('context'); 12 13 var a = document.createElement('a'); 14 a.setAttribute('href', data[i][0]); 15 context.appendChild(a); 16 17 var content = document.createElement('div'); 18 content.classList.add('content'); 19 20 var content2 = document.createElement('div'); 21 content2.classList.add('item-header'); 22 23 var content3 = document.createElement('a'); 24 content3.classList.add('profile'); 25 26 var content4 = document.createElement('span'); 27 content4.classList.add('name'); 28 content4.insertAdjacentHTML('afterbegin',data[i][1]); 29 30 var content5 = document.createElement('small'); 31 content5.classList.add('time'); 32 content5.insertAdjacentHTML('afterbegin',data[i][2]); 33 34 content3.appendChild(content4); 35 36 content2.appendChild(content3); 37 content2.appendChild(content5); 38 //div.content 39 content.appendChild(content2); 40 41 42 var elmc = document.createElement('div'); 43 elmc.classList.add('text-container'); 44 var elmc2 = document.createElement('p'); 45 elmc2.classList.add('comment'); 46 elmc2.insertAdjacentHTML('afterbegin',data[i][3]); 47 //div.text-container 48 elmc.appendChild(elmc2); 49 50 var elmf = document.createElement('div'); 51 elmf.classList.add('item-fotter'); 52 var elmf2 = document.createElement('span'); 53 elmf2.classList.add('reply'); 54 var elmf3 = document.createElement('span'); 55 elmf3.classList.add('retweet'); 56 //div.item-fotter 57 elmf.appendChild(elmf2); 58 elmf.appendChild(elmf3); 59 60 //div 61 content.appendChild(elmc); 62 content.appendChild(elmf); 63 64 div.appendChild(context); 65 div.appendChild(content); 66 fragment.appendChild(div); 67}

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kei344

2017/10/01 16:47

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

2017/10/01 17:02

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

2017/10/01 17:05

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

回答3

0

ベストアンサー

テンプレート機能は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 追記 サンプル

HTML

1<template id="hoge"> 2 <div> 3 <div class="context"> 4 <a href="http://localhost:3000"></a> 5 </div> 6 <div class="content"> 7 <div class="item-header"> 8 <a class="profile"><span class="name">名前</span></a> 9 <small class="time">YYYY-MM-DD</small> 10 </div> 11 <div class="text-container"> 12 <p class="comment">コメント内容</p> 13 </div> 14 <div class="item-fotter"> 15 <span class="reply"></span> 16 <span class="retweet"></span> 17 </div> 18 </div> 19 </div> 20</template> 21<!-- polyfill --> 22<script src="template.js"></script>

JavaScript

1document.addEventListener('DOMContentLoaded', function(event) { 2 var data = [["URLA","名前A","日付A","コメントA"],["URLB","名前B","日付B","コメントB"],["URLC","名前C","日付C","コメントC"]]; 3 4 var fragment = document.createDocumentFragment(); 5 var content = document.getElementById('hoge').content; 6 7 for (var i = 0, len = data.length; i < len; i++) { 8 var clone = content.cloneNode(true); 9 clone.querySelector('.context a').href = data[i][0]; 10 clone.querySelector('.name').textContent = data[i][1]; 11 clone.querySelector('.time').textContent = data[i][2]; 12 clone.querySelector('.comment').textContent = data[i][3]; 13 fragment.appendChild(clone); 14 } 15 16 document.body.appendChild(fragment); 17});

投稿2017/10/02 02:25

編集2017/10/04 05:33
x_x

総合スコア13749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

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

lang

1<script id="template" type="x-tmpl-mustache"> 2{{#items}} 3<div> 4 <div class="context"> 5 <a href="{{url}}">link</a> 6 </div> 7 <div class="content"> 8 <div class="item-header"> 9 <a href="" class="profile"><span class="name">{{name}}</span></a> 10 <small class="time">{{date}}</small> 11 </div> 12 <div class="text-container"> 13 <p class="comment">{{comment}}</p> 14 </div> 15 <div class="item-fotter"> 16 <span class="reply"></span> 17 <span class="retweet"></span> 18 </div> 19 </div> 20</div> 21{{/items}} 22</script> 23 24<div id="target">Loading...</div>

lang

1const data = { 2 items: [ 3 {url: "111.jp", name: "name1", date: "date1", comment: "comment1"}, 4 {url: "222.jp", name: "name2", date: "date2", comment: "comment2"}, 5 ] 6} 7 8const template = document.getElementById('template').innerHTML 9const rendered = Mustache.render(template, data) 10document.getElementById('target').innerHTML = rendered

投稿2017/10/01 18:06

karamarimo

総合スコア2551

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

JavaScript

1let a = `<div> 2 <div class="context"> 3 <a href="http://localhost:3000"></a> 4 </div> 5 <div class="content"> 6 <div class="item-header"> 7 <a href="" class="profile"><span class="name">名前</span></a> 8 <small class="time">YYYY-MM-DD</small> 9 </div> 10 <div class="text-container"> 11 <p class="comment">コメント内容</p> 12 </div> 13 <div class="item-fotter"> 14 <span class="reply"></span> 15 <span class="retweet"></span> 16 </div> 17 </div> 18</div>`, b = "", data2; 19var data = [["Jan","Feb","Mar","Apr"],["a", "b", "c", "d"]]; 20data2 = data.reduce( ( pre, curr )=> { 21 pre.push.apply( pre, curr ); 22 return pre; 23}, [] ); 24data2.forEach( curr => { 25 b += a.replace( '名前', curr ); 26} ); 27document.body.insertAdjacentHTML("beforeend", b ); 28 29```**動くサンプル:**[https://jsfiddle.net/3khdk7k9/1/](https://jsfiddle.net/3khdk7k9/1/) 30 31--- 32 33 34【Array.prototype.reduce() - JavaScript | MDN35[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) 36 37【Array.prototype.forEach() - JavaScript | MDN38[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) 39 40【配列の連結(concat vs Array.prototype.push.apply) - Qiita】 41[https://qiita.com/kaz2ngt/items/6e08acc537fd77273cff](https://qiita.com/kaz2ngt/items/6e08acc537fd77273cff)

投稿2017/10/01 16:32

kei344

総合スコア69364

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

elelboo

2017/10/01 16:52

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問