getElementBy〜を色々作ってみたのですが……
最近、急に寒くなってついに毛布を出したyukiinu2ndです。
久々に(?)JavaScriptネタです。
所用で「getElementByTagNameFromChildNodes」のような自作のDOM取得メソッドを作ったりしていました。
以下のようにこのままグローバルに置いたりしてもよいのですが……。
var getElementByTagNameFromChildNodes = function(tagname,pos,from){ var nodes = from.childNodes; var cnt = 0; for(var i = 0;i < nodes.length;i++){ if(nodes[i].tagName == tagname.toUpperCase()){ if(cnt == pos) break; cnt++; } } return nodes[i]; };
これだと他のDOM取得メソッドと「.」でつなげて呼べなくて少し不便です……。
//現実は…… var targetElement = getElementByTagNameFromChildNodes("div",2,document.getElementById("Hoge1")); //本当はこう呼び出したい! var targetElement = document.getElementById("Hoge1").getElementByTagNameFromChildNodes("div",2);
そこで、HTML上の要素の元となっているクラスである「HTMLElement」を拡張してみます。
この拡張にはprototypeチェーンと呼ばれる仕組みを使います。
あるオブジェクトがプロパティを参照しようとした際、自身のオブジェクトに参照しようとしたプロパティが無かった場合、そのオブジェクトを生成したオブジェクトのprototypeプロパティの中を探す、という処理を再帰的に行います。
よって、拡張はprototypeプロパティに新しいプロパティを定義することで行えます。
※かなり端折っていることと、これであっているのか正直不安ですが……。間違えていたら指摘お願いします。
HTMLElement.prototype.getElementByTagNameFromChildNodes = function(tagname,pos){ var nodes = this.childNodes; var cnt = 0; for(var i = 0;i < nodes.length;i++){ if(nodes[i].tagName == tagname.toUpperCase()){ if(cnt == pos) break; cnt++; } } return nodes[i]; }; //これで取得できる! var targetElement = document.getElementById("Hoge1").getElementByTagNameFromChildNodes("div",2);
これで問題なし……といきたいところですが、IEではうまく動きません。
実は、IEではprototypeチェーンが使えないという致命的な問題があるためです……。
対策としては、HTC(HTML Component)を使ったり、documentをラップしたものを作って拡張するなど、様々な方法があるようです。
実際にそこまでは試せなかったですが、機会があれば追ったり試したりしてみようと思います。