DOM検索効率化のメソッド群を作ってみた。
というわけで、もういっちょ。考えていたDOM検索効率を考えたメソッド群を作ってみた。
ええと、prototype.jsのElementオブジェクトにaddMethodsしていることからもわかるようにprototype.js必須っす。ええと、私の使っているprototype.jsは、1.5.1ね。script.aculo.us(v1.7.1_beta3)と一緒に使っているので。
document.getElementsByClassNameAndTagName = function(className, parentElement, tagName) {
if (Prototype.BrowserFeatures.XPath) {
return $(parentElement).getElementsByClassName(className);
} else {
var children = $(parentElement).getElementsByTagName(tagName || '*');
var elements = [], child;
for (var i = 0, length = children.length; i < length; i++) {
child = children[i];
if (Element.hasClassName(child, className))
elements.push(Element.extend(child));
}
return elements;
}
}
Element.addMethods({
getElementsByClassNameAndTagName: function(element, className, tagName) {
return document.getElementsByClassNameAndTagName(className, element, tagName);
},
nextElement: function(element) {
do {
element = element.nextSibling;
} while (element && element.nodeType != 1);
return $(element);
},
previousElement: function(element) {
do {
element = element.previousSibling;
} while (element && element.nodeType != 1);
return $(element);
},
firstChildElement: function(element) {
var child = element.firstChild;
while (child && child.nodeType != 1) {
child = child.nextSibling;
}
return $(child);
},
lastChildElement: function(element) {
var child = element.lastChild;
while (child && child.nodeType != 1) {
child = child.previousSibling;
}
return $(child);
},
childElements: function(element) {
var children = [];
var child = element.firstChild;
while (child) {
if (child.nodeType == 1) {
children.push($(child));
}
child = child.nextSibling;
}
return children;
},
childElement: function(element, index) {
var nodeIndex = 0;
var child = element.firstChild;
while (child) {
if (child.nodeType == 1 && index == nodeIndex++) {
return $(child);
}
child = child.nextSibling;
}
return null;
},
cleanWhitespaceRecursive: function(element) {
var f = function(element) {
var child = $(element).cleanWhitespace().firstChild;
while (child) {
if (child.nodeType == 1) {
f(child);
}
child = child.nextSibling;
}
};
f(element);
return element;
}
});
nextElement, previousElementはそのまんま。textNodeはすっ飛ばして、elementNodeだけを見ている。firstChildElementとlastChildElementはfirstElementとlastElementって命名しようかと思ったけど、childだということを意識したかったのでちょいと冗長だけど、これで堪忍してや。で、意味もそのまんま。textNodeをすっ飛ばして最初や最後のelementNodeを返す。
childElementsは、前回のポストの結果を考慮してfirstChildとnextSiblingを採用。elementNodeの配列を返す。childElementは、index指定でelementNodeを返す。本当は、こんな感じでchildElementsメソッドの返す配列のindexを返す方がすっきりしていていいんだけどなぁ。
childElement: function(element, index) {
return $(element).childElements()[index];
},
しかし、それだとnextSiblingを全て見てまわってしまうので、遅くなりそうなので、不採用。
cleanWhitespaceRecursiveはついでの産物。今回作成したものとは関係がないのだけども、一応。HTMLコーダにじかにHTMLを書かれるとwhitespaceが入ってしまい、困るので再帰的に消してみることにした。JavaScriptで再帰をするときってやっぱり、ローカル変数に関数をぶちこんで、それを何度も呼び出す方がいいのかな、と思ったので、自分自身を何度も呼び出すような方は不採用。
自分自身を呼び出すのは、こんな感じか。
cleanWhitespaceRecursive: function(element) {
element = $(element);
var child = element.cleanWhitespace().fistChild;
while (child) {
if (child.nodeType == 1) {
child.cleanWhitespaceRecursive();
}
child = child.nextSibling;
}
return element;
}
どっちがいいんだろうなぁ。。。
で、本当は、オプションで、$指定で返すか、そのままのelementを返すかを指定できるようにするかで迷ったのだけど、prototype.jsと一緒に使うことを前提としているので、$で返すようにした。これもパフォーマンスに関係してくるんだけど、まぁ、その辺は考慮中。
つーか、また後で追記したり、ソース修正するかもしれん。名前はなんでもよかったのだけど、domx.jsとしよう。
< !DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
ソースはここ。
domx.js
ライセンスは適当っす。自己責任で使ってちょ。
で、上のソースを動かす形にしたデモもここに置いておく。domx demo
うーん。そろそろjQuery使ってみようかなぁ。。。onReadyとか便利そうだし。。。インデントがタブなのが非常に嫌なので、敬遠しているのだけど。。。
全然関係ないが、ここ二日ほど愛知県図書館で開発をしている。なかなか良いね。ホットスポットもあるみたいだけど、契約をしていないのでインターネットにつなげない。でも、そのおかげで効率がいいよん。インターネットがあるとダラダラしちゃって、ダミだ。
Shin Ohno 2003-2012