Hatena::ブログ(Diary)

三等兵

2010-08-23

JavaScriptのDOM Core基礎

Coreの簡易リファレンス。Coreは要素を参照したり、相対位置から周りのノードを参照したり、要素を生成するといった部分。主に利用するであろうプロパティやメソッドはカバーしているつもりですけど、これも入れとけってのあったら教えてください。

このあたりは地味で使いづらくその上理解しにくいという残念な部分。ふと忘れたときに使う個人的なものですが、慢性jQuery拒絶症候群な人よかったらどうぞ。それにしても暑い。ガリガリ君おいしいね。

DOMとは。

Document Object Model (DOM) は、HTML および XML ドキュメントのための API です。これはドキュメントの構造的な表現を提供し、内容や表示形態の変更を可能にします。端的に言えば、Web ページをスクリプトやプログラミング言語とつなぐような機構です。

https://developer.mozilla.org/ja/DOM

※追記

※ブラウザのバージョンはFirefox3.6.8, Google Chrome5.0.375.127, Opera10.61, IE8をさし、IE9ppはIE9とする。その他適当に。


基本的な要素の参照

document.getElementById()

id属性値から要素を参照。

var d = document.getElementById('box');
alert(d.id); // box

// html
<div id="box">暑い</div>

document.getElementsByName()

name属性値から要素を参照。

//js
var elems = document.getElementsByName('dom');
alert(elems[0].value); // 最初
alert(elems[1].value); // 真ん中
alert(elems.length); // 3

// html
<input name="dom" type="text" value="最初" />
<input name="dom" type="text" value="真ん中" />
<input name="dom" type="text" value="最後" />
  • プロパティ
    • length
  • メソッド
    • item(index)
  • 戻り値
    • Firefox, IEはHTMLCollection型のオブジェクト
    • Google Chrome, OperaはNodeList型のオブジェクト

仕様や書籍などではNodeListとあるがHTMLCollectionもあったらしい。扱う分にはどっちも似たようなもので、namedItemてメソッドがNodeListにはない。

よく言われているように、HTMLCollectionやNodeListは配列のような振る舞いをするけど配列そのものではないので注意。


IEやOperaでは、

//js
var elems = document.getElementsByName('dom');
alert(elems[0].value) // 最初
// html
<input id="dom" type="text" value="最初" />

id属性でもgetElementsByNameで参照できたりする。そしてIE6,7とOpera9では、

//js
var elem = document.getElementById('dom');
alert(elem.value) // 最初
// html
<input name="dom" type="text" value="最初" />

逆もある。IE8とOpera10.60では参照できないようになっていた。意図せずname属性とid属性の値を同じにしない。


document.getElementsByTagName()

タグ名から要素を参照。

//js
var lists = document.getElementsByTagName('li');
alert(lists[1].firstChild.nodeValue); // 真ん中
alert(lists[2].firstChild.nodeValue); // 最後
alert(lists.length); // 3

// html
<ul id="list">
  <li>最初</li>
  <li>真ん中</li>
  <li>最後</li>
</ul>
  • プロパティ
    • length
  • メソッド
    • item(index)
  • 戻り値
    • Firefox, IEはHTMLCollection型のオブジェクト
    • Google Chrome, OperaはNodeList型のオブジェクト

HTMLCollectionやNodeListはlists[i]だけでなくlists.item(i)という形でも要素を取り出せるが、メソッド使うよりは配列の記法が良いらしい。メソッドだと遅いからか。

forでまわすとき。http://cou929.nu/data/google_javascript_style_guide/#id57

var lists = document.getElementsByTagName('li');
for (var i = 0, list; list = lists[i]; i++) {
  doSomething(list);
}

falseとして扱われる値を含まないコレクションや配列であれば、NodeList以外でもこう書ける。

NodeListを配列として扱うなら方法はいくつかあるが普通に代入が無難。

var lists = nlToArray(document.getElementsByTagName('li'));

function nlToArray(nodelist) {
  if(nodelist instanceof Object) 
    return Array.prototype.slice.call(nodelist);

  var r = [], i = 0, l = nodelist.length;
  for(;i < l; i++) {
    r[i] = nodelist[i];
  }
  return r;
}

一応の方法Array.prototype.slice.callも。弾さんが教えてくれた方法(これはargumentsでの例)はIEだとエラー。JScriptはHTMLCollectionやNodeListをJScriptのオブジェクトとして認識しないらしい。IE9からは大丈夫。

document.getElementsByTagNameはワイルドカードも指定できる。ただしIE6,7,8は要素以外にもコメントノードが含んでしまうので注意。DOCTYPEもコメントノードに含まれる。

//js
var lists = document.getElementsByTagName('*');
alert(lists.length); // 5(普通はコメントノードを除いて4でなければならない)

// html
<ul id="list">
  <li>最初</li>
  <li>真ん中</li>
  <li>最後</li>
  <!-- コメコメ -->
</ul>

document.getElementsByClassName()

クラス属性値から要素を参照。

//js
var items = document.getElementsByClassName('item');
alert(items[0].firstChild.nodeValue); // 最初
alert(items[2].firstChild.nodeValue); // 最後
alert(items.length); // 3

// html
<ul id="list">
  <li class="item">最初</li>
  <li class="item">真ん中</li>
  <li class="item">最後</li>
</ul>
  • プロパティ
    • length
  • メソッド
    • item(index)
  • 戻り値
    • Firefox, IEはHTMLCollection型のオブジェクト
    • Google Chrome, OperaはNodeList型のオブジェクト

戻り値はgetElementsByName/TagNameと同じ。Firefox3, Opera9.5, Safari3.1, Google Chromeの時点で、IEはIE9でネイティブで実装されている。


document.evaluate()

XPathで要素を参照。

//js
var result = document.evaluate('id("list")//li', document, null, 7, null);
alert(result.snapshotItem(0).firstChild.nodeValue); // 最初

// html
<ul id="list">
  <li>最初</li>
  <li>真ん中</li>
  <li>最後</li>
</ul>
  • プロパティ
    • snapshotLength
    • その他いくつか
  • メソッド
    • iterateNext()
    • snapshotItem(itemNumber)
  • 戻り値
    • XPathResult型のオブジェクト

IE9未実装。IE以外はだいたい使える。XPathひとりでできないもんは、http://pearl-white.hp.infoseek.co.jp/xpath/が便利。個人的に苦手。

引数については以下を参照。多い。


querySelector()とqueryselectorAll()

CSSセレクタで要素を参照。

// querySelector
var list = document.querySelector('ul#list > li');
alert(list.firstChild.nodeValue); // 最初

// querySelectorAll
var lists = document.querySelectorAll('ul#list > li');
alert(lists[1].firstChild.nodeValue); // 真ん中
alert(lists[2].firstChild.nodeValue); // 最後
alert(lists.length); // 3

// html
<ul id="list">
  <li>最初</li>
  <li>真ん中</li>
  <li>最後</li>
</ul>
  • プロパティ
    • length
  • メソッド
    • item(index)
  • 戻り値(querySelectorAll)
    • Firefox, Google Chrome, OperaでNodeList型のオブジェクト
    • IE8とIE9はStaticNodeList型のオブジェクト。なんじゃごら

2つのメソッドの違いは要素数が単体か集合かというところ。IE8から実装されているので、そろそろこれが何も気にせず使えるようになればみんな恍惚とした表情に。

戻り値はいずれのブラウザでもstaticなNodeListと珍しい。


子ノードの参照

element.childNodes

その要素のすべての子ノードを参照。

//js
var list = document.getElementById('list');
alert(list.childNodes[1].firstChild.nodeValue); // 最初
alert(list.childNodes.length) // 7(IE6,7,8などは3)

// html
<ul id="list">
  <li>最初</li>
  <li>真ん中</li>
  <li>最後</li>
</ul>
  • プロパティ
    • length
  • メソッド
    • item(index)
  • 戻り値
    • NodeList型のオブジェクト

lengthプロパティを使ってul#listの子ノードを数えると、FirefoxやGoogle Chromeなどは7つで、IEは3つとなる。これは空白ノードを認識するかしないかの違い。

Firebug*1のコンソールでchildNodesの中身をみると、

console.log(list.childNodes);
//<TextNode textContent="\n ">, li, <TextNode textContent="\n ">, li, <TextNode textContent="\n ">, li, <TextNode textContent="\n">

TextNodeのテキスト内容は改行と半角スペースで、liがli要素にあたる。これを視覚的に分かりやすくすると。

<ul id="list"><TextNode textContent="\n
 "><li>最初</li><TextNode textContent="\n
 "><li>真ん中</li><TextNode textContent="\n
 "><li>最後</li><TextNode textContent="\n">
</ul>

これらを含めli要素と空白ノード合われせば7つ。IE8以下はこういった空白ノードが無く、li要素だけなので3だったということ。こういった相対的な位置から要素を参照するときは空白ノードに注意。

この邪魔な空白ノードを除いて必要なli要素だけを取り出す。

var list = document.getElementById('list');
var cn = list.childNodes;
var r = [], i = 0, l = cn.length;

for(; i < l; i++) {
  if(cn[i].nodeType === 1) {
    r.push(cn[i]);
  }
}
alert(r.length); // 3
console.log(r) // li, li, li

空白ノードはテキストノードにあたるため、nodeTypeを調べて要素ノード以外を除くことでFirefoxなどでもul#listの子li要素だけ取得できる。ただし、このケースはdocument.getElementById('list').getElementsByTagName('li')が無難。

nodeTypeについては後述


element.firstChild

その要素の最初の子ノードを参照。

//js
var list = document.getElementById('list');
alert(list.firstChild); // <li>最初</li>

// html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

今後面倒だからインデントと改行を排除し空白ノードを含めない。

たとえば、上記の状態から「最初」という文字列を取得するには、

//js
var list = document.getElementById('list');
alert(list.firstChild.firstChild.nodeValue); // 最初

// html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

とする。


element.lastChild

その要素の最後の子ノードを参照。

//js
var list = document.getElementById('list');
alert(list.lastChild); // <li>最後</li>

// html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

たとえば、ここからさらに「最後」という文字列を取得するなら、

//js
var list = document.getElementById('list');
alert(list.lastChild.firstChild.nodeValue); // 最後

// html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

とする。


element.hasChildNodes()

その要素が子ノードを持っているかどうか調べる。

//js
var list = document.getElementById('list');
alert(list.hasChildNodes()); // true
while(list.firstChild) {
 list.removeChild(list.firstChild); // 子ノードを全て削除
}
alert(list.hasChildNodes()); // false

// html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>
  • 戻り値
    • 子ノードがあればtrue
    • 子ノードが無ければfalse

子ノードの有無が不確定な場合に重宝する。


親ノードの参照

element.parentNode

その要素の親にあたるノードを参照。

// js
var li01 = document.getElementsByTagName('li')[0]; // <li>最初</li>の要素
alert(li01.parentNode.id) // list

//html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

element.ownerDocument

その要素が含まれるトップレベルのドキュメントオブジェクトを参照。

// js
var list = document.getElementById('list'); 
var d = list.ownerDocument;
alert(d); // document
alert(d === document); // true
alert(document.ownerDocument); // null
alert(document.createTextNode('').ownerDocument); // document

list.parentNode.removeChild(list); // DOMから要素を削除
alert(list.ownerDocument); // document

//html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

ブラウザ上ではたいがいdocumentになる。DOMツリーに挿入していなくても、またツリーから削除しても取得できる。


兄弟ノードの参照

element.previousSibling

その要素の直前のノードを参照。

// js
var li02 = document.getElementsByTagName('li')[1]; // <li>真ん中</li>の要素
alert(li02.previousSibling.firstChild.nodeValue) // 最初

//html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

簡単にいえば、この場合childNodes[1]からchildNodes[0]を参照できるのがpreviousSibling。


element.nextSibling

その要素の直後のノードを参照。

// js
var li02 = document.getElementsByTagName('li')[1]; // <li>真ん中</li>の要素
alert(li02.nextSibling.firstChild.nodeValue) // 最後

//html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

この場合childNodes[1]からchildNodes[2]を参照できるのがnextSibling。


ノードの操作

node.nodeValue

そのノードの値を参照。

// js
var par = document.getElementById('syouji');
alert(par.firstChild.nodeValue); // 平成の
alert(par.lastChild.firstChild.nodeValue); // パピプペポ

// html
<p id="syouji">平成の<em>パピプペポ</em></p>

このように、HTML文書では主にテキストノードに対して扱うことが多い。

人間の目に優しくする。

<p><TextNode textContent="平成の"><em><TextNode textContent="パピプペポ"></em></p>

ここはノード、エレメント(要素)、タグの違いと、テキストもノードだということが分かると理解しやすい。

http://www.atmarkit.co.jp/fxml/askxmlexpert/015tagelement/15tagelement.html

http://taro4.blog37.fc2.com/blog-entry-26.html


読み書きどちらもいけるので値を変更することもできる。

// js
var par = document.getElementById('syouji');
par.firstChild.nodeValue = '昭和の';

// html
<p id="syouji">平成の<em>パピプペポ</em></p>
// js実行後html
<p id="syouji">昭和の<em>パピプペポ</em></p>

テキストノード以外でnodeValueを扱う例としては、属性ノードの値があげられる。

// js
var par = document.getElementById('syouji');
alert(par.getAttributeNode('id').nodeValue); // syouji

// html
<p id="syouji">平成の<em>パピプペポ</em></p>

getAttributeNodeというメソッドを使い属性ノードとして参照し、そのノードの値を取得している。ただし、こうして扱うことはあまりない。この場合素直にpar.idとするか、par.getAttirbute('id')で十分。


node.nodeName

そのノードの名称を参照。

// js
var par = document.getElementById('syouji');
alert(par.nodeName); // P
alert(par.firstChild.nodeName); // #text
alert(par.lastChild.nodeName); // EM

// html
<p id="syouji">平成の<em>パピプペポ</em></p>

要素ノードについてはelement.tagNameと同じでその要素名を大文字で返す。ほかのノード名称の戻り値については以下を参考に。


このプロパティを扱う機会はあまり無いかもしれない。


node.nodeType

ノードの種類を参照。

// js
var par = document.getElementById('syouji');
alert(par.nodeType); // 1
alert(par.getAttributeNode('id').nodeType); // 2
alert(par.firstChild.nodeType); // 3

// html
<p id="syouji">平成の<em>パピプペポ</em></p>

要素ノードは1、属性ノードは2、テキストノードは3を返している。getAttributeNodeについてここでは詳しく扱っていないので気になるのならばこちらを参考に。付け加えておくと、HTML文書ではまず扱えなくても問題ないのでこのページでは取り上げていない。

ほかのノードの種類については以下を参考。


上記URL先は英語なので、ここでは日本語とそれに対する数値の表も残しておく。覚える必要はなく分からなければメモしておくか、この表を見返せば問題ない。

概要概要
1要素ノード7処理命令ノード
2属性ノード8コメントノード
3テキストノード9文書ノード
4CDATAセクション10文書型宣言ノード
5実体参照ノード11文書の断片
6実体宣言ノード12記法宣言ノード

タグの属性操作

element.getAttribute()

タグの属性値を取得。

// js
var img = document.getElementById('pimg');
var urlprop = img.src; // プロパティでの取得方法
alert(urlprop); // src属性が表示

var urlmethod = img.getAttribute('src'); // メソッドでの取得方法
alert(urlmethod); // src属性が表示

// html
<img src="http://img.f.hatena.ne.jp/images/fotolife/s/sandai/20100403/20100403192301.jpg" id="pimg">

プロパティからの方法とメソッドを使う方法がそれぞれある。


class属性値は誰もが通る道。

// js
var par = document.getElementById('kamille');
var badcls = par.class; // class属性値を取得しているつもりだが
alert(badcls) // undefined or エラー
var goodcls = par.className; // 'className'とすれば
alert(goodcls) // char と取得できる

// html
<p id="kamille" class="char">そんな大人!修正してやる!</p>

par.getAttribute('class')とメソッドを使えば大体'class'でも大丈夫だが、IE7まではpar.getAttribute('className')としなければならず、こうすると今度は他のブラウザでclass属性値が取得できない。

class属性値に限ってはメソッドを使わずpar.classNameが無難。


あとIE6,7については属性値でなく要素のプロパティを参照してしまう。だから、たとえばこのようなことができる。

// js
var par = document.getElementById('kamille');
alert(par.getAttribute('innerHTML')); // そんな大人!修正してやる!

// html
<p id="kamille" class="char">そんな大人!修正してやる!</p>

属性にinnerHTMLはないので通常はnullを返さなければならないが、IE6,7はpar.innerHTMLと解釈しているため要素の内容を返してしまう。その他style属性なども同じで、getAttributeすると大変なことになるので注意。IE8からは大丈夫。


element.setAttribute()

タグの属性値書き込み。

// js
var par = document.getElementById('kamille');
par.className = 'gundam' // プロパティからclass属性値修正
alert(par.className); // gumdam

par.setAttribute('id', 'newtype') // メソッドからid属性値修正
alert(par.id); // newtype

// html
<p id="kamille" class="char">そんな大人!修正してやる!</p>
// js実行後のhtml
<p id="newtype" class="gumdam">そんな大人!修正してやる!</p>

構文

要素.setAttribute(属性名, 属性値)

プロパティからの方法とメソッドを使う方法がある。


新しい属性値も設定できる。

// js
var par = document.getElementById('kamille');
par.className = 'char'; // プロパティから
par.setAttribute('title', 'これが若さか'); // メソッドから

// html
<p id="kamille">そんな大人!修正してやる!</p>
// js実行後html
<p id="kamille" class="char" title="これが若さか">そんな大人!修正してやる!</p>

element.getAttribute()と同じくIE7以下は属性値でなく要素のプロパティを参照してしまうので注意。たとえばstyle属性の値を設定するときうまくいかない。

// js
var par = document.getElementById('kamille');
par.setAttribute('style', 'color:#000');

// html
<p id="kamille">そんな大人!修正してやる!</p>
// js実行後html
<p id="kamille" style="">そんな大人!修正してやる!</p>

par.style = 'color:#000'みたいに解釈されているため値が設定されていない。このメソッドからstyle属性を操作することはあまりないけれど一応注意。IE8からは大丈夫。


element.removeAttribute()

タグの属性削除。

var par = document.getElementById('kamille');
par.removeAttribute('id'); // id属性を削除 

// html
<p id="kamille" class="char">そんな大人!修正してやる!</p>
// js実行後html
<p class="char">そんな大人!修正してやる!</p>

これもelement.getAttribute()と同じくIE7以下は属性値でなく要素のプロパティを参照してしまうので注意。IE8からは大丈夫。


document.createAttribute()

属性ノードを生成。

// js
var par = document.getElementById('kamille');
var t = document.createAttribute('title'); // 属性ノード生成
t.nodeValue = "これが若さか"; // 属性ノードに値を挿入
par.setAttributeNode(t);

// html
<p id="kamille">そんな大人!修正してやる!</p>
// js実行後html
<p id="kamille" title="これが若さか">そんな大人!修正してやる!</p>

あまり使わない。setAttributeNodeメソッドもあまり使わない。元ネタが分からなければつまらない。


element.attributes

タグの属性を全て取得。

// js
var img = document.getElementById('pimg');
var attrs = img.attributes; // 全ての属性を取得

var r = [], i = 0, l = attrs.length;
for(; i < l; i++) {
  if(attrs[i].nodeValue) {
    r.push(attrs[i].nodeName + ' : ' + attrs[i].nodeValue);
  } 
}
alert(r.toString()); // border : 0,alt : pyonco,id : pimg,src : http://img.f.hatena.ne.jp/images/fotolife/s/sandai/20100403/20100403192301.jpg

// html
<img src="http://img.f.hatena.ne.jp/images/fotolife/s/sandai/20100403/20100403192301.jpg" id="pimg" alt="pyonco" border="0">
  • プロパティ
    • length
  • メソッド
    • item(index)
    • getNamedItem(name)
    • removeNamedItem(name)
    • setNamedItem(node)
  • 戻り値
    • NamedNodeMap型のオブジェクト

IE7以下はelement.attributesプロパティはその要素(element)以外の属性まで出力されるので注意。よくわからなければIE7以下でjsのコードを下記に変えて試してみる。

var img = document.getElementById('pimg');
var attrs = img.attributes; // 全ての属性を取得

var r = [], i = 0, l = attrs.length;
for(; i < l; i++) {
  r.push(attrs[i].nodeName + ' : ' + attrs[i].nodeValue);
}

IE8からは大丈夫。その他のモダンブラウザはまずこんなことはない。


element.hasAttribute()

タグの属性に指定の属性があるかどうか調べる。

// js
var img = document.getElementById('pimg');
alert(img.hasAttribute('id')) // true
alert(img.hasAttribute('align')) // false

// html
<img src="http://img.f.hatena.ne.jp/images/fotolife/s/sandai/20100403/20100403192301.jpg" id="pimg" alt="pyonco" border="0">
  • 戻り値
    • あればtrue
    • 無ければfalse

IE7以下では使えない。


ノードの生成、追加、削除等の操作

document.createElement()

要素を生成。

// js
var d = document.getElementById('box');
var par = document.createElement('p'); // p要素生成
par.id = 'par';
par.innerHTML = 'ガリガリ君を食べたい'
d.appendChild(par);

// html
<div id="box"></div>
// js実行後html
<div id="box"><p id="par">ガリガリ君を食べたい</p></div>

appendChildについては後述。ガリガリ君については今すぐ小一時間語ってもいい。


document.createTextNode()

テキストノードを生成。

// js
var d = document.getElementById('box');
var txt = document.createTextNode('ガリガリ君に会いたい'); // 生成
d.appendChild(txt);
console.log(txt); // <TextNode textContent="ガリガリ君に会いたい">

// js実行後html
<div id="box">ガリガリ君に会いたい</div>

textContentはnodeValueプロパティにあたる。IE8まではtextContentは扱えない。これはDOM Level 3で定義されている。ただし、ガリガリ君は定義されていなかった。


element.appendChild()

その要素の一番最後の子ノードとして追加。

// js
var list = document.getElementById('list');
var li = document.createElement('li');
li.innerHTML = '最後尾';
list.appendChild(li);

//html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>
// js実行後html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li><li>最後尾</li></ul>

構文

親要素.appendChild(追加ノード)

element.insertBefore()

その要素の指定した子ノードの前にノードを追加。

// js
var li01 = document.getElementById('list').firstChild;
var li = document.createElement('li');
li.appendChild(document.createTextNode('先頭いただき'));
li01.parentNode.insertBefore(li, li01);

//html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>
// js実行後html
<ul id="list"><li>先頭いただき</li><li>最初</li><li>真ん中</li><li>最後</li></ul>

構文

親要素.insertBefore(追加ノード, 追加ノードの前にあるノード)

element.removeChild()

その要素の子ノードを削除。

// js
var li01 = document.getElementById('list').firstChild;
li01.parentNode.removeChild(li01);

//html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>
//js実行後html
<ul id="list"><li>真ん中</li><li>最後</li></ul>

構文

親要素.removeChild(削除ノード)

element.replaceChild()

その要素の子ノードを別の新しいノードに置き換える。

// js
var li01 = document.getElementById('list').firstChild;
var li = document.createElement('li');
li.appendChild(document.createTextNode('ガリガリ君死す'));
li01.parentNode.replaceChild(li, li01);

//html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>
//js実行後html
<ul id="list"><li>ガリガリ君死す</li><li>真ん中</li><li>最後</li></ul>

構文

親要素.replaceChild(置き換えるノード, 元々のノード)

element.cloneNode()

要素をコピーする。

// js
var li01 = document.getElementById('list');
var li01clone = li01.cloneNode(true);
document.body.appendChild(li01clone);

// html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>
// js実行後html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>

引数はtrueかfalse。trueであれば上記のように子要素までコピーされる。引数にfalseを入れた場合の実行結果。

//js実行後html
<ul id="list"><li>最初</li><li>真ん中</li><li>最後</li></ul>
<ul id="list"></ul>

子要素はコピーされない。


document.createDocumentFragment()

要素を収容する容器みたいなもの。

// js
var d = document.getElementById('box');
var df = document.createDocumentFragment();
var txt = document.createTextNode('ガリ');

for(var i = 0; i < 100; i++) {
df.appendChild(txt.cloneNode(true)); // 100回テキストノードを挿入
}
d.appendChild(df);

//html
<div id="box"></div>
// js実行後html
<div id="box">ガリガリガリガリガリガリガリガリガリガリガリ.....</div>

引数は必要ない。あと寿司にでてくるガリではない。ガリガリ君のガリ。

この容器はDOMツリーには追加されることはなく、生成した要素を一時的に収容させておくもので、それらの要素をDOMツリーに一度に挿入するときに利用する。

だから、

for(var i = 0; i < 100; i++) {
d.appendChild(txt.cloneNode(true));
}

とするよりはDocumentFragment使った方が良い。情報が少ないから気づきにくい。


element.normalize()

その要素内のテキストノードを正規化。隣接するテキストノードの結合と、空白ノードの削除をしてくれる。

// js
var d = document.getElementById('box');
var txt01 = document.createTextNode('お腹と背中が');
var txt02 = document.createTextNode('くっつくぞ!');
d.appendChild(txt01)
d.appendChild(txt02)

alert(d.childNodes.length); // 2
d.normalize(); // 隣接したテキストノードを結合
alert(d.childNodes.length); // 1

// html
<div id="box"></div>

隣接したテキストノードが結合され1つのノードになったことがlengthプロパティからわかる。

空白ノードの削除も、

//js
var d = document.getElementById('box');
var txt01 = document.createTextNode('');
d.appendChild(txt01);
alert(d.childNodes.length); // 1

d.normalize(); // 空白ノードを削除
alert(d.childNodes.length); // 0

// html
<div id="box"></div>

削除された。ただし、生成して挿入した空白ノードについてはこのように削除されるが、元々のhtmlソースのインデントやスペースは削除対象にならない。


Log

  • 2010/12/21
  • 2010/09/06
  • 2010/09/02
    • getElementsByClassName, evaluate, querySelector/SelectorAllに注記
    • 「ノードの操作」のカテゴリを新しく設置
  • 2010/08/25
    • IE8やIE7の開発ツール注意書き付け足し
    • getElementsByTagNameのワイルドカードについて
    • 属性の部分をいろいろ変更
      • IE6,7のget,set,removeAttributeに関する補足
      • 順番変えた
      • コードも少し変えた

*1:IE8は開発者ツールを立ち上げてからでないとconsole.logがエラーを返す。IE7などはFirebug Liteなどインストールを

rikubarikuba 2010/08/24 12:55 > element.nodeValue
要素ノードのnodeValueは常にnullなので、Node.nodeValueなどとした方が良いと思います。
(余談:テキストノードとコメントノードにはdataもありますね)

他にも、IE9で足並みが揃うElement Traversal(firstElementChildなど)も紹介してはいかがでしょうか。

think49think49 2010/08/24 19:00 気が付いた点をちらほらと。


・document.getElementsTagName('*') で IE8 はコメントノードまで拾います。
・element.ownerDocument があるなら、document.defaultView (IE は document.parentWindow) も説明があるといいかもしれません。
・element.removeAttribute() も element.setAttribute() と同じく、IEは属性ノードではなくプロパティを参照します。
・IE8 は開発者ツールを立ち上げない状態で、console.log() を使うと「オブジェクトでサポートされていないプロパティまたはメソッドです。」のエラーを返します。IE7- は Firebug Lite などの開発者ツールをインストールしないとダメだと思います。一言注意書きがあるといいかもしれません。

think49think49 2010/08/24 23:42 > ・element.removeAttribute() も element.setAttribute() と同じく、IEは属性ノードではなくプロパティを参照します。
「IE7- は属性ノードではなくプロパティを参照します」に訂正。
IE8 で修正済みの不具合でした。

IE8での変化点一覧 + 備忘録 - latest log
http://d.hatena.ne.jp/uupaa/20081027/1225107483

sandaisandai 2010/08/25 00:41 >rikubaさん
ありがとうございます。nodeValueはその通りです。
というかテキストノードは子を持たないので、そもそもここにあるのがおかしいですね。
やってしまった。こいつの身の振りを考えます。
Element Traversal便利ですね。入れておきます。

>think49さん
ありがとうございます。TagName付け足しときます。
document.defaultViewはViewsだったので外しましたが、
そういえば普通にstyleいじってるなぁ・・・。
removeAttrとsetAtterは見逃してました。参考のURLもありがとうございます。
cssのプロパティじゃなくて、innerTextとかできるということですね。ひどい。
console.logはIEは無視して示せば良いかぐらいで使ったのですが、
やっぱりだめですね。注意入れておきます。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証