サイトマップ

JavaScriptコードスニペット:CSSセレクタで要素を取得する

DOMドキュメントの任意の要素を取り出す方法にはXPathを使うというものがありますが、例によってInternet Explorerでは使えないという問題があります。ではCSSセレクタはどうでしょうか?

これにはW3C Selectors APIというのがあって、FireFoxは実装していますがInternet Explorer 8未満では以下同文という状況のようです。そこは、無いのなら作ってしまえほととぎすという話です。ここではあえて既に実装されているAPIを上書きしています。

CSSセレクタの仕様を完全に実装する必要もなく、JavaScriptから特定の要素を取り出すのに便利な方法が提供できればよいので、

  • 要素名による指定
  • クラス名による指定(1つのみ)
  • idによる指定

とそれらの組合せのみを実装しています。(そもそもそんなにCSSセレクタの仕様をしらないのですが)

なお、要素名を省略したときのパフォーマンスが非常に悪化し、特にIEでは顕著となります。つまり、できるだけ上位の指定で要素名を指定して絞り込んだ方がパフォーマンスは有利となります。

document.querySelectorAll = function(selectors, node) {
    var result = [];
    result.item = function(i) { return this[i]; };
 
    if (!node) node = document;
    if (!selectors) { return result; }
 
    //console.log(selectors + " from " + node.nodeName);
    if (selectors.match(/^([\w\d]+)?((\.[\w\d\-_]+)|(#[\w\d\-_]+))?\s*/)) {
        var ename = RegExp.$1;
        var cname = RegExp.$3;
        var iname = RegExp.$4;
        selectors = RegExp.rightContext;
 
        if (ename && ename != '*') { //tag name
            var childs = node.getElementsByTagName(ename);
            for (var i = 0; i < childs.length; i++) {
                result.push(childs.item(i));
            }
        } else {
            //arguments.calleeで無名関数を再帰的に呼び出す。
            (function(curr) {
                if (curr.nodeType != 1 && curr.nodeType != 9) return;
                result.push(curr);
                for (var i = 0; i < curr.childNodes.length; i++) {
                    arguments.callee(curr.childNodes.item(i));
                }
            })(node);
        }
 
        if (cname) { //class name filter
            var pattern = new RegExp(' ' + cname.substring(1) + ' ');
            for (var i = result.length - 1; i >= 0; i--) {
                var item = result.item(i);
                var clazz = (item.className ? item.className : item.styleClass);
                if (!(' ' + clazz + ' ').match(pattern))
                    result.splice(i, 1);
            }
        }
 
        if (iname) { //id filter
            iname = iname.substring(1);
            for (var i = result.length - 1; i >= 0; i--) {
                var item = result.item(i);
                if (item.id != iname)
                    result.splice(i, 1);
            }
        }
 
        if (selectors.match(/\S+/)) {
            var childs = new Array();
            childs.item = function(i) { return this[i]; };
 
            for (var i = 0; i < result.length; i++) {
                var q = document.querySelectorAll(selectors, result.item(i));
                for (var j = 0; j < q.length; j++) {
                    childs.push(q.item(j));
                }
            }
            result = childs;
        }
        return result;
    }
}
document.querySelector = function(selectors) {
    return document.querySelectorAll(selectors).item(0);
}

【サンプルの実行】
見つかった要素の背景の色が変わります。

関連コンテンツ

 
research/1309735292.txt · 最終更新: 2011/07/04 15:36 by Kazuyuki Matsuda
特に明示されていない限り、本サイトの内容は次のライセンスに従います:Copyright(C) 2011 Shorindo, Inc. All Rights Reserved
Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki