2008-03-06
IE8 で実装された Selectors API とは何か?
JavaScript, CSS, IE
はじめに
IE8 には Selectors API という新しい仕様が実装されました。
ということで、今後 DOM 操作 API の主流になるであろう Selectors API についてまとめておきます。
Selectors API が使えるブラウザ
2008 年 3 月 6 日現在の一覧
Selectors API とは
Selectors API とは W3C で定義された仕様です。詳細に関してはこちらをどうぞ
簡単に説明すると
getElementsByTagName や getElementsByName や getElementById などの DOM のオブジェクトを取得するメソッドありますよね。
あれの「すごい版」の querySelector や querySelectorAll というメソッドのことを指します。
たとえば、既存の getElementsByTagName などのメソッドの代わりに Selectors API を使うと以下のようになります。
// 以下の二つは同じ要素を取得する var nl00 = document.getElementsByTagName('div'); var nl01 = document.querySelectorAll('div'); alert(nl00[0] == nl01[0]); // true alert(nl00[1] == nl01[1]); // true : : // 以下の二つは同じ要素を取得する var elm00 = document.getElementById('target'); var elm01 = document.querySelector('#target'); alert(elm00 == elm01); // true // 以下の二つは同じ要素を取得する var nl02 = document.getElementsByName('hoge'); var nl03 = document.querySelectorAll('*[name="hoge"]'); alert(nl02[0] == nl03[0]); // true alert(nl02[1] == nl03[1]); // true : :
どうですか?簡単ですね?
querySelector や querySelectorAll には、 CSS セレクタを渡す。
前の例を見て気が付く方も多いと思いますが、 querySelector や querySelectorAll には CSS セレクタを渡します。
CSS セレクタとは、 CSS の中カッコの前に書かれる要素を特定するための文字列のことですね。
たとえば、以下の例で言うと
ul.navigation li { display: inline; }
「ul.navigation li」が CSS セレクタにあたります。
(追記) 疑似クラスの扱い
id:vantguarde さんから以下のようなはてブコメントを頂きましたので、疑似クラスについて追記します。id:vantguarde さんありがとうございます!
擬似クラスなノードも取得できるってのを書いてほしいかも。
はてなブックマーク - vantguarde - 2008年3月6日
おっしゃるとおり Selectors API では疑似クラスにも対応しています。
たとえば、
// 現在選択されている要素を取得 var elm00 = document.querySelector(':focus'); // 現在マウスが乗っかってる要素を取得 var elm01 = document.querySelector(':hover'); // elementFromPoint と等価
このような感じになります。
ただ、プライバシーの配慮か単なるバグなのかは分かりませんが IE8 では :visited 疑似クラスは取得できませんでした。
alert(document.querySelectorAll('a:visited').length); // 常に 0
(追記) カンマで複数の CSS セレクタを指定できます。
カンマ自体が CSS セレクタの仕様の一部なので、当たり前と言えば当たり前ですが、これも書いておきます。
// 以下のように、カンマを使って複数の CSS セレクタを指定することもできます。 document.querySelectorAll('span, strong'); // span と strong 要素をすべて取得
querySelector と querySelectorAll の違い
querySelector と querySelectorAll の違いは、これも、最初の例で分かると思いますが、取得する要素が一個か複数かの違いです。
querySelector の場合は、そのセレクタが選択する要素の一番最初の要素だけを取得し、 querySelectorAll の場合はすべての要素を取得します。
例えば、以下のような HTML があったとします。
<html> ..(略).. <body> <ul><li>aaa</li><li>bbb</li><li>ccc</li></ul> </body> </html>
そうすると、 querySelector は以下のようになります。
var elm = document.querySelector('body > ul > li'); alert(elm.innerHTML); // aaa
このように、 querySelector は HTML を上から順*1に見て一番最初に出て来た要素を選択します。
また、 querySelectorAll は以下のようになります。
var nl = document.querySelectorAll('body > ul > li'); alert(nl.length); // 3 alert(nl[0].innerHTML); // aaa alert(nl[1].innerHTML); // bbb alert(nl[2].innerHTML); // bbb
このように、 querySelectorAll も HTML を上から順*2に格納しています。
つまり、
document.querySelector(selector) // は document.querySelectorAll(selector)[0] // と等価
ということです*3。
querySelectorAll で取得される値
次は、 querySelectorAll で取得される値についてです。
// すべての要素を取得 var nl = document.querySelectorAll('*'); alert(nl instanceof Array); // false // push などの配列のメソッドは使えない try { nl.push('hoge') } catch (e) { alert('error') } // error // 使えるのは length だけ alert(nl.length);
ここまでは、従来の getElementsByTagName などで取得される値と同じです。
しかし、 querySelectorAll で取得される値の性質は getElementsByTagName などで取得される値とも少し違っています。
// すべての要素を取得 var nl00 = document.getElementsByTagName('*'); var nl01 = document.querySelector('*'); // ここで、 HTML の内容を書き換える(要素を一つ削除する) document.body.removeChild(document.body.getElementsByTagName('*')[0]); alert(nl00.length == nl01.length); // false alert(nl00.length); // こちらは、変更が反映されて一つ少ない値になる alert(nl01.length); // こちらは、変更が反映されない(取得時の状態)
このように、取得後に HTML の構造が変化した場合その変化を反映させるかさせないかの違いがあります。
また、それぞれのオブジェクトの名前を NodeList 、 StaticNodeList といいます。
| NodeList | getElementsByTagName などで取得される値 | 値取得後の HTML の構造の変化をその場で反映する |
| StaticNodeList | querySelector で取得される値 | 取得時の状態のままで、変化が反映されない |
一見、 getElementsByTagName の仕様のほうが便利に思えますが、この動的な性質があったせいで処理が重くなっていたんですね。
だから、 querySelectorAll は取得した値の操作が軽いかもしれませんね。
document だけじゃなく、要素からも使えます。
今までは、 document.querySelectorAll とやってきましたが、普通に要素でも使えます。
要素で、実行した場合は子孫要素から要素が選択されるようになります。
var elm = document.querySelector('#target'); // elm の子孫要素で hoge というクラスを持つ要素 elm.querySelectorAll('.hoge'); // つまり、 #target .hoge と同じ
まとめ
こんな感じです!超便利ですね!
DOM 3 XPath 派な僕ですが。やっぱり IE8 が Selectors API を実装したので、これから Selectors API の時代が来ると思います。
他のブラウザも早く実装して欲しいですね!
この便利なメソッドが使えるようになるのは非常に楽しみです><
ではでは!
(Namespace については省略しました。)
- WEB開発日記 - IE8 で実装された Selectors API とは何か? - IT戦記
- shiroicaの日記
- This is one of the web’s most interesting stories on Thu 6th Ma...
- 無題
- cimadaiの日記 - IE8 で実装された Selectors API とは何か?
- cimadaiの日記 - IE8 で実装された Selectors API とは何か? - IT...
- くらげのChangeLog - IE8 で実装された Selectors API とは何か? -...
- 野村直之の日記: IT - とくにメタデータ - , 音楽
- INOHILOG - Operaのタブを整理
- 【ブラウザ】IE8 b1 技術概要
- 素人がプログラミングを勉強するブログ - FirefoxのtrunkにSelector...
- Cherenkovの暗中模索にっき - Twitterの自分のつぶやきを一括削除す...
- 主に言語とシステム開発に関して - Prototype.js のはまり所
- juiceeeeeの喉が渇いた - (memo)DOMとか
- クライアント・サイド・スクリプティング with Web Standards - Nic...
- 愛と勇気と缶ビール - mixiをしていたごく普通のOLが、何故NodeList...
- Selenium初心者 - SelectorsAPI
- 1765 http://www.new-akiba.com/archives/2008/03/ie8javascript.html
- 899 http://reader.livedoor.com/reader/
- 863 http://b.hatena.ne.jp/hotentry
- 502 http://d.hatena.ne.jp/
- 303 http://b.hatena.ne.jp/
- 257 http://www.google.com/reader/view/
- 223 http://www.google.co.jp/ig?hl=ja
- 218 http://b.hatena.ne.jp/entrylist?sort=hot
- 187 http://www.google.co.jp/reader/view/
- 142 http://phpspot.org/blog/archives/2008/03/200837.html
