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

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

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

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

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

2回答

2739閲覧

documentFragmentの内容がリセットされる?

Meganezaru

総合スコア715

JavaScript

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

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2017/01/17 06:52

###やりたいこと
子要素の内容を書き換えるために、一旦documentFragmentで操作をして、親要素を更新しようとしています。

###問題点
下記コードを実行しても、子要素の内容が書き換わりません。
forEach内でdivの値を確認すると、内容が書き換わっているように見えます。その状態で、documentFragmentに追加していますが、実際にDOMに展開されるのは、変更前の"-"になってしまいます。

試しに、forEachの外側で、documentFragmentに子要素を追加すると、それは、DOMに反映されました。

クロージャ?レキシカルスコープ?のようなモノが、何か影響しているように感じたのですが・・・理解しきれていなく・・・

きっと、仕様をよく理解出来ていないことが原因の単純なミスだと思うのですが、いろいろ調べても、原因がつかめず、質問させていただきました。

よろしくお願いします。

html

1<div id="wrapper"> 2 <div id="1">-</div> 3 <div id="2">-</div> 4 <div id="3">-</div> 5</div>

JavaScript

1 $(function(){ 2 var dict = {"1": 1, 3 "2": 2, 4 "3": 3}; 5 6 var documentFragment = document.createDocumentFragment(); 7 8 var keys = Object.keys(dict); 9 keys.forEach(function(key){ 10 var div = $("#" + key).clone(); 11 div.html = String(key * 10); 12 $(documentFragment).append(div); 13 dict[key] = key * 10; 14 }); 15 $('#wrapper').html(documentFragment); 16 });

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

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

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

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

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

guest

回答2

0

ベストアンサー

雑感

DOM API と jQuery API を混同して覚えているような印象を受けます。

  • jQuery#html は関数です。プロパティではありません。従って、div.html = String(key * 10); は期待通りに動作しません。
  • jQuery#html は DocumentFragment を認識しません。DOM API の appendChild を使ってください。⇒これは誤りでした。jQuery#html はDOMノードも扱えるようです(詳細は後述)。

jQuery#html の仕様

説明すると長くなるのでQiitaにまとめました。

修正コード

質問文のコードの体裁を残したコードがこちら。

HTML

1<div id="wrapper"> 2 <div id="1">-</div> 3 <div id="2">-</div> 4 <div id="3">-</div> 5</div> 6<script> 7'use strict'; 8jQuery(function (jQuery) { 9 var dict = {"1": 1,"2": 2,"3": 3}, 10 documentFragment = document.createDocumentFragment(); 11 12 Object.keys(dict).forEach(function (key) { 13 var value = key * 10, 14 div = jQuery("#" + key).clone(); 15 16 div.text(value); 17 dict[key] = value; 18 documentFragment.appendChild(div[0]); 19 }); 20 jQuery('#wrapper').html(documentFragment); 21}); 22</script>

上記コードには下記問題があります。

  • id属性値が数字から始まっている(HTML5 では許されるが、セマンティック上好ましくない)
  • 変数 dict が再構成されている(動的に生成するなら初期値が不要)
  • 生成した DocumentFragment を jQuery オブジェクトでラップしているので変換コストが勿体ない
  • 要素ノードをごっそり入れ替えているので当該要素ノードにイベント定義されていたら全てはがされてしまう

問題を修正したコードがこちら。

HTML

1<div id="wrapper"> 2 <div id="sample-1">-</div> 3 <div id="sample-2">-</div> 4 <div id="sample-3">-</div> 5</div> 6<script> 7'use strict'; 8jQuery(function () { 9 var dict = Object.create(null); 10 11 jQuery('#wrapper>div').text(function (index) { 12 var id = this.id, 13 value = id.replace(/^[a-z-]+/, '') * 10; 14 15 dict[this.id] = value; 16 return value; 17 }); 18 19 console.log(JSON.stringify(dict)); // {"sample-1":10,"sample-2":20,"sample-3":30} 20}); 21</script>

更に Object.definePropertydict に getter/setter を与えてやると良い感じになりそうです。

更新履歴

  • 2017/01/17 17:06 修正コードを追記
  • 2017/01/17 19:25 jQuery#html の仕様を追記

Re: Meganezaru さん

投稿2017/01/17 07:01

編集2017/01/17 10:27
think49

総合スコア18162

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

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

Meganezaru

2017/01/17 07:37

ご回答、ありがとうございました! とても、恥ずかしい内容で申し訳ないです(笑) jQuery.html(documentFragment)は動いているように見えるのですが、たまたまなんですかね?
think49

2017/01/17 08:13

失礼しました。jQuery.html(documentFragment) も確かに動くようです。 ただ、公式リファレンスによれば jQuery.html は String 型を引数にとるので今後も使える事が保証されているかは分かりません。 http://api.jquery.com/html/ 親記事を追記しました。
Meganezaru

2017/01/17 09:02

追加のご回答ありがとうございました! わかっている人が書くと、コードがすっきりしますね。参考にさせていただきます。 今回のコードは、実際のコードの問題を再現した(つもりだった)コードだったので、実は、まだ問題は解決していないのですが、もう少し粘って考えてみます。 documentFragmentについては、参照すると、内包している要素のHTMLStringが返される実装のように感じました。(詳しく調べたわけではないので、違っていたらごめんなさい・・・)
think49

2017/01/17 10:28

> documentFragmentについては、参照すると、内包している要素のHTMLStringが返される実装のように感じました。 こちらで検証したところでは df + '' も String(df) も "[object DocumentFragment]" を返したので多分、違うと思います。 ソースコードを読む限りでは jQuery オブジェクトへの変換処理が入っているような…。 http://qiita.com/think49/items/affdd59c1791e2a04b6c https://github.com/jquery/jquery-ui/blob/master/external/jquery-3.1.1/jquery.js#L5978
Meganezaru

2017/01/18 00:26

やはり、違ってましたね・・・(笑) どこかで、logの表示にHTMLタグが表示されているの見たことをうろ覚えしてた程度の根拠でした・・・ Qiitaへのまとめもありがとうございました。 大変勉強になります。 jQueryを含め、JavaScriptはまだまだ理解が浅いので、出来る限り理解を深めていきたいと思います。 お恥ずかしい質問でしたが、お付き合いありがとうございました。
guest

0

すいません・・・やっぱり単純なミスでした(笑)
div.html = "xxxxx"ではなく
div.html("xxxxx")ですね(;´∀`)

投稿2017/01/17 07:00

Meganezaru

総合スコア715

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問