◆ li が入ってる ul にたくさんの li を追加したいときとか

document fragment というと要素をまとめておいて一気に追加するための機能ですが意外と使う機会がないです


たいてい 要素を作る時って
funciton makeElem(arr){
var ul = document.createElement("ul")
arr.forEach(function(e){
var li = document.createElement("li")
li.textContent = e
ul.appendChild(li)
})
return ul
}
makeElem(["abc","def","ghi","jkl"])
こういう 1つの要素の下に色々付いてる構造をつくるか
function makeElem2(obj){
var elem = templateElem.cloneNode(true)
Object.keys(obj).forEach(function(key, _, t){
var selector = key
var fn = t[key]
fn(elem.querySelector(selector))
})
return elem
}
makeElem2({
".xyz": e => e.classList.add("abc"),
"ul>li:first-child": e => e.classList.remove("li"),
"input.word": e => e.value = ""
})
こういう テンプレートをクローンして一部を書き換えたもののどちらかになってます

DOM に要素を繰り返しつけると遅いと言われてますが こういう関数で作った要素を 1つつけるだけなので特に document fragment が必要ないです

DOM に要素を付けると遅いといっても最近では 最適化が進んでますし JavaScript の処理をすべて実行してしまってから時間のかかる表示部分を最後に処理するみたいなので setTimeout で別の処理にせず一回の JavaScript の関数実行内で全部やってたら変わらないんじゃないかと思います
ベンチマーク取ったわけじゃないので責任はもてませんけど



そういうわけで全然使われない document fragment なんですが 珍しく役立つ場面に出会いました

すでに ul に li がいくつか入っています
そこに ある処理で作られる li のリストを加えたいです

forEach でそれぞれに対して li を生成するのといっしょに appendChild してもいいですが 上側の makeElem のように関数では li をまとめて返して 外側で ul に加えるように分割したいです
要素を生成する関数では生成だけで 外側の DOM に手を加えるのは避けたいんです
ですが 配列で返して外側でまたループして 1つ1つ appendChild ってなんかムダな感じがして気持よくないです

そんなときに document fragment!
<ul><li>1</li><li>2</li><li>3</li></ul>
var text = "a,b,c"
var dfrag = document.createDocumentFragment()
text.split(",").forEach(function(e){
var li = document.createElement("li")
li.textContent = e
dfrag.appendChild(li)
})

var ul = document.querySelector("ul")
console.log(ul, ul.children)
console.log(dfrag, dfrag.children)

ul.appendChild(dfrag)
console.log(ul, ul.children)
console.log(dfrag, dfrag.children)
<ul>...</ul> [li, li, li]
#document-fragment [li, li, li]
<ul>​…​</ul> ​ [li, li, li, li, li, li]
#document-fragment []

こういう感じに使えます

document fragment の要素を appendChild するとその中の要素全部に appendChild したようになります
固まりを 1 つ追加するのじゃなくて 固まりの中身をそれぞれ追加する感じです

appendChild をすると document fragment 内の要素は全部消えてしまいます
消したくないなら cloneNode したものを appendChild すればいいです


cloneNode 以外にも HTML エレメントに使えるメソッドが色々使えます
firstChild や getElementId や querySelector などなどです