IIJmio(みおふぉん)

HTMLエレメントObject指定

初心者向けの、HTMLタグオブジェクトの指定方法です。
basicな古い基本的な方法から今のDOM時代の方法まで。

操作対象を指定するには状況に応じていくつも方法があります。

■ 基本的な方法 と メソッド ■ Tips (応用編)
document.getElementById()

最も使われているIDからオブジェクトを指定する方法がこれです。
タグにIDをつければIDでいきなりオブジェクト指定できるので、 全体のオブジェクト構造など気にする事無く初心者でもすぐに使える最も一般的な方法と言えます。

誰の親、誰の子など全く気にする事無く

document.getElementById(id)
(idは文字列なら 'id'、"id")

で、ピンポイントでオブジェクト指定ができます。
この時 getElementById の記述で大文字と小文字は絶対に守る事。
document.allの使えるIE、OperaではこのgetElementById(name)でもオブジェクト指定できるケースがあります。 これはJavaScript基礎部分の方法でも可能な特定タグに関してだけですし、Netscape系では全く通用しないので nameは使えないと思い込んでしまっても良いです。IE専用の開発であればもっと楽な方法もありますし。

documentが先頭に着く必要を考えればわかると思いますが、documentのメソッドです。 従って他のウィンドウやフレームの場合は、そのウィンドウのdocument指定する形を取ります。

document.getElementById()と言う記述は、たかがIDからオブジェクトを指定するのにはとても長い記述です。 最も頻繁に使われてるメソッドの一つなのに何故こんな長い名前にしたんだ?って感じです。
で、一部 prototype.jsなどの有名ライブラリで使ってる事から真似する人も非常に増えている、 $という1文字の短縮系にする方法も簡単です。
私の場合はGet_Objとか、byIDと言うのを以前から利用していました。 これだけの為ならprototype.jsを使う必要は全くないので自分でショートカット用関数を作りましょう。

関数名は自分の好きに。例 $ を使うならば
function $(id){ return document.getElementById(id); }
これで短縮できます。この関数をスクリプトに入れれば $(id) で取れます。
ただしこのままだgetElementById()メソッドを理解できないブラウザではここでエラーが出るので、 エラーを出さずに静かに拒否したり(出た方が判りやすい場合もある)、このメソッドが使えるか?のチェックも兼ねさせてしまいます。

function $(id){
    if( document.getElementById ){
        return ( id !== undefined ) ? document.getElementById(id) : true;
    }
    return false;
}
この関数の状態で

$()
の様にIDを入れない状態で参照すれば、document.getElementById()と言うメソッドが使えれば true、 使えなければ false が戻るようになっています。 処理開始の時点でDOM対応ブラウザかどうかを調べる時に使います。
例:始動場所の関数やイベントハンドラなど冒頭で
if(!$()) return false;
の様にして未対応ブラウザの場合は処理を拒否。或いは メッセージを出します。
if(!$()){ alert('JavaScriptが対応していません'); return false; }

$(id)
の様にidを入れれば、document.getElementById(id)を実行します。
これだけで対象IDのエレメントをHTMLオブジェクトとして指定する事になります。
IDが存在しなければ null と言う特殊なオブジェクトの状態になります。
注意深くエラーを出さないように使うのであれば
if( $(id) ){ $(id).style・・・・ }
の様に一旦そのIDが存在しているのか?を問う事も忘れないように。
null値になった物をそのまま使うとエラーが出ますから。

この関数は一例です。
自分で工夫して、自分のプログラムで使いやすいように、オブジェクト指定以外にも必要な情報を使えるようにしておく手もあります。

例: (わかりやすく長く書きます)
function $(id){
    if( document.getElementById ){ //getElementByIdが使えるか?
        if( id !== undefined ){ //IDが引数にあるか?
            if(document.getElementById(id)){ //そのIDが存在するか?
                var obj = document.getElementById(id);
                obj.htm = obj.innerHTML;
                //プロパティ名が有効なテキスト値を取る
                obj.txt = ( obj.value || obj.innerText || obj.textContent );
                return obj;
            }
            return null;
        }
        return true;
    }
    return false;
}
自作 $ の拡張例として、ちょっと丁寧に書いてあります。
プログラム中でinnerHTMLやinnerText(NetscpapeだとtextContent)を取り出すことが多い場合、 innerHTMLやinnerText、textContent、value(フォームエレメントの場合)の値をとる短縮形もつけてしまうと便利です。
(NetscapeではinnerTextもtextContentも使えないので微妙ですが・・・)
この関数の場合は、先ほどまでの使い方に加えて
$(id).htm で 対象が内包する HTML表記文字を返します。
$(id).txt で 対象が内包する 表示上のテキスト文字列。フォームエレメントの場合はvalue値を返します。
たいした拡張ではありません。
.htm はinnerHTMLと言う表記を短くする効果しかありません。
.txt はIEとNetscape系でのテキスト文字の取り方の違いと、フォームエレメントの場合の取り方の違いをこの関数で処理してしまう事で、 コーディング中では $(id).txt とするだけなので楽になります。

短縮形はそもそもDOMを先駆けて使えたIE4等のdocument.allとその後のdocument.getElementByIdを、どちらでも使えるようにその差異を関数の中で処理する事も目的でした。 私はまだそうしていますが、アクセス解析を見てもIE4は0%に等しいです。 私は下位ブラウザが理解出来る程度の簡単なJavaScriptを書く時は下位ブラウザを切り捨てないと言う考えです。 が、もうIE6以上を基準にしても全く問題ないと思います。

と言うのがつい最近、Microsoftが自動UPDATEでIE7の自動インストールを開始すると言うニュースがありました。 それまでは銀行や大手のオンラインサービスのIE7対応が遅れていて、自動インストールしてしまうとそれらの サービスを利用してるユーザーが困るので自動ではなく選択にしていたようです。 オンラインサービスのIE7への対応がほとんど終了したとの事で、自動インストールに踏み切ったようです。

昔ながらの方法

初心者ページのオブジェクトで、JavaScriptの基礎部分でのHTMLのオブジェクト構造を説明しました。 この昔ながらの方法はその基礎部分に沿った方法です。
今のDOM時代では色んな呪文(メソッド)でオブジェクトを指定できますからあまり使わなくなっていますが、 基礎の部分を知っておく事で呪文が通じない時に便利な場合があるので解説しておきます。

JavaScriptは今の様に全ての要素を扱えるようになる前から、 代表例としてフォーム(とその部品)、イメージ、アンカーなどは扱えるように出来ています。 逆に言えば、これらを扱う為にJavaScriptであったとも言えます。

ですからJavaScriptはページが読み込まれた時点で
fomrs
elements(個々のformの部品)
options(更にselectの場合の子)
images
anchors
等のHTMLの超基礎要素の配列をdocument下に自動的に生成します。
そのタグの集合配列って言う事で、配列名に s が付いてるのもわかりやすいですね。
これらの配列はインデックス型の普通配列とキー型(name属性)の連想配列の両方です。
これらを基本の上層からのオブジェクト指定方法で書く事で対象を指定することが出来ます。

■ 配列indexから

自分自身のウィンドウ内なら最上層( window )を省けますので

このドキュメントの1個目のアンカー(タグ)
document.anchors[0]

このドキュメントの1個目の画像(タグ)
document.images[0]

このドキュメントの1個目のフォーム(タグ)
document.forms[0]

このドキュメントの1個目のフォーム(タグ)の中の1個目のエレメント
document.forms[0].elements[0]
フォームとエレメントは主従関係で2重配列になってるので
document.forms[0][0]
と言う書き方で省略可能です。

■ 配列キーから

anchorsは元々はname指定を用意していなかったようで

<a name='a1' >というタグ
document.anchors['a1'] Netscape
document.anchors('a1') IE
となります。

<img name="img1"> と言うタグ
document.images['img1']

<form name="form1"> と言うタグ
document.forms['form1']

<form name="form1">にある<input name="el1">の様な部品
document.forms['form1'].elements['el1']
フォームとエレメントは主従関係で2重配列になってるので
document.forms['form1']['el1']

■ name属性でそのまま

frames、images、forms、などはこの方法が出来ます。
anchorsは元々はname指定を用意していなかったようで無理です。
またdivなど用意されていない物も無理です。

<img name="img1"> と言うタグ
document.img1

<form name="form1"> と言うタグ
document.form1

<form name="form1">にある<input name="el1">の様な部品
document.forms1.el1



また、これらの方法を混ぜこぜにしてもOKです。
document.forms[0].el1

さて、これらの方法だと常にオブジェクトの最上層から書く為に 例えば他のフレームで極端な例ですが、あるフレームのselectで選択されている値をとる時は
top.frames[0].document.forms[0].elements[0].options[top.frames[0].document.forms[0].elements[0].selectedIndex].value (1行つながりです)
top.fr1.document.form1.el1.options[top.fr1.document.form1.el1.selectedIndex].value(1行つながりです)

の様に長くてミスもしやすく特定もしにくと言うのが現実でした。
もちろん一旦変数にオブジェクトを入れて
var sel = top.fr1.document.form1.el1;
sel[sel.selectedIndex].value;
の様に書くのが当たり前ですが、
それでもオブジェクト構造を意識しないと駄目なので面倒でした。

フォーム部品に関しては未だに送信の際にname属性を必要とするので、 たいして操作をしない場合などはIDもつけずに
document.forms1.el1
の様に使う事は今でも普通に行われています。

このBasicな方法とID等からの指定などを混同してしまってる人がいますが、 結果的にオブジェクトを指定できれば良いとは言っても、違う方法である事は意識してください。
どういう意図でどういう方法を使ってるかは明確に意識して偶然に頼らないように。


document.all() /allコレクション

いち早くドキュメント全体を操作対象と考える方法をMicrosoftのIE4が実装しました。
それがこの document.allで全てのIDとJavaScriptの基本部分でも使えるケースのnameを allというコレクションにして、 その id や name からオブジェクト指定できるようにした方法です。
tagsコレクションなどもあり今現在のDOMとあまり変りの無いものでした。
現在(IE7やOpera9、Safari)も実装されていてかなり便利なのですが、逆に迷惑?なケースもあります(^^ゞ

■ document.all()

使い方は簡単です。一応どのタグでもタグに id をつければ、

document.all(id) ( idが文字列ならクォートで囲む )

で、対象をオブジェクトとして指定できてしまいます。
また、前述の昔ながらの方法で name を利用できるIMG、FORM、FORMのエレメントなどに関しては idではなくnameの場合もdocument.all()で利用できます。

<div id="div1"> </div> なら
document.all('div1')

<form id="form1"> や <form name="form1">なら
document.all('form1')

■ document.all を 省略

このdocument.allが便利だった所は、ID (FORM、IMAGEなどの場合はnameも)さえあれば document.allを省略する事も可能だった点です。
(formの子エレメントはこの方法は駄目)
<div id="div1"> </div> なら
div1

<form id="form1"> や <form name="form1">なら
form1
だけで、もう既にそのオブジェクトを指定してるのと同じ事になります。
これでとてもスマートなコーディングができるようになっていました。

つまりIDやname(特定のタグだけ)がつけてある場合はドキュメントが読み込まれた時点で、 そのIDやnameがオブジェクトが代入されたグローバル変数として自動的に定義されていた事になります。

逆にこの便利すぎる部分が迷惑な部分にもなっていました。
ドキュメント内のID名が全てグローバル変数として予約されてしまうのはちょっと迷惑です。 気をつければよい事ですが、大きいファイルになるとちょっとね(^^ゞ
またスクリプトが本格的になればなるほど、無駄にグローバル変数や関数は作りたくないですし。

ま、document.allはIE専用の開発以外では出番がほとんどなくなりました。
IEもすでに説明したNetscape系と共通のdocument.getElementById()を使えますので、 document.allしか持たないIE4まで含めた開発をする時以外はあまり使いません。
アクセス解析を見ててもIE4は見かける事はほとんどありません。0に近いです。


document.getElementsByName()

これはドキュメント内のnameコレクションから指定nameで抽出するものです。

document.getElementsByName(name)

getElementById()と違い getElementsByName()の様にsが着いてる事からも、
指定した戻り値が配列である事が想像つきますね?。

IDはユニークな物でないといけない決まりですが、nameはフォームではラジオボタンなど同じ物が存在する場合があります。
従ってnameでは特定せずに一旦配列として取るようになっています。
配列(コレクション)なのでその要素はitem(index)として取り出します。
item()を使わず普通の配列の様に指定しても大丈夫です。
また、配列なのでlengthプロパティで要素数もわかります。

document.getElementsByName(name).item(index)
document.getElementsByName(name)[index]
(indexは配列のindexなので数値)

document.getElementsByName(name).length
(nameで見つかった数)

通常は同じnameは1個しか使わない事がほとんどですし、自分のHPですからその辺は把握してると思いますので、1個の場合なら
document.getElementsByName(name)[0]
で、対象を指定できる と言う事になります。

ただし、このdocument.getElementsByName()は使い勝手が悪いです。

IEでは前述してるJavaScriptの基礎の方法でnameが使える物にしか作用しません。 が、ついでにnameじゃなくてidでもこの byNameで取れてしまいます。
つまりIEはこのメソッドで指定できるのはdocument.allコレクションと同じ物である と言う事です。

Netscape系ではDIVやSPANタグにnameをつけて利用できますがIEでは無理です。
IEだとDIVやSPANタグにIDをつけて、このメソッドで取れますがNetscape系では無理です。

と言う事で、IE、Netscape系共通で使えるのは、JavaScriptの基礎部分でname指定取りができるHTMLタグに限られます。 IMG、FORM、FORM部品、などです。
ま、時代的にname属性はフォーム以外ではあり得ない時代でもありますので、使えなくても差し支えないでしょう。
が、前述のIEとNetscape系の特徴(癖)を考えて逆手に取ると、タグにIDとNAME属性両方が同じ名前で設定されていれば、 getElementsByTagNameが広範囲で使えると言う事にもなります。 ま、そこまでしっかりHTML側を組んでるならID指定すれば良いわけですが・・・。 プログラムを組んでると『あとづけ』などで『どうしてもこの状態で通したい』と言うような状況物出てきますから、 全体をスマートで洗練された方法に書き換えるよりは、多少無駄でも・・・と言う方法をとることもあります。 臨機応変に利用してください。

何らかの状況でdocument.getElementsByName()を使う時はこのブラウザによる特性の違いに気をつけてください。


Object.getElementsByTagName()

これはドキュメント内、または指定したオブジェクト(タグエレメント)の内包要素から、 指定したtagnameに該当するものを抽出するメソッドです。

これも getElementsByTagName()の様にsが着いてる事からも、
指定した戻り値が配列である事が想像つきますね?。

document.getElementsByTagName(tagname)

document.getElementsByTagName("*")
"*"はタグを特定せず全てのタグを取る時のワイルドカードです。

ドキュメント全体からSTYLEタグを抽出
document.getElementsByTagName('style')

ドキュメントのBODY内から特定のタグを抽出
document.body.getElementsByTagName('img')

ある特定のDIVエレメント内からIMGタグを取る
例:div に id='div1' が設定されている場合。
document.getElementById('div1').getElementsByTagName('img')

この様に絞り込んだ特定範囲内からの抽出もできます。

ある特定のtableからtdタグ(全てのセル)を取る
例:table に id='table1' が設定されている場合。
document.getElementById('table1').getElementsByTagName('td')


この抽出した配列は普通配列と連想配列式、両方使える状態になっています。
この配列を処理しながら条件に合う物だけ抽出するなどの作業が必要になります。
基本は配列なので長さは
object.getElementsByTagName(tagname).length

個々の要素は
object.getElementsByTagName(tagname).item(0)
object.getElementsByTagName(tagname)[0]
の様に配列indexで指定できます。

個々の要素にIDがあれば
object.getElementsByTagName(tagname)["id"]
object.getElementsByTagName(tagname).id
(このIDは実際のID名。プロパティ名がIDと言う意味とは別)
の様に指定する事も出来ます。
ま、最初からIDを使うならbyTagNameを使うケースはあまり無いですけど。

Object.getElementByTagName()は、非常に便利です。
でも甘い設計を補う為の手抜き用に使うのはあまり良い事ではないです。
状況に応じてこの方が汎用性、優位性がある場合のみ使うような方法です。

例えば、こんな使い方をします。
ある DIV内にサムネイルが100個並んでいるとして、DIVのidがthumbs とします。
この100個の画像全てにonclickイベントをつけて画像拡大させる場合 IDの有無とは関係なく面倒です。
こういう場合に
var Imgs = document.getElementById('thumbs').getElementsByTagName('img');
for(var i=0; i<Imgs.length; i++){
Imgs[i].onclick = function(){ 拡大実効命令 }
//または
Imgs[i].onclick = Larger; //関数へのハンドラー等
}
の様に特定の小範囲の内包要素の該当要素全てに処理をする必要がある場合などには向いてると思います。

ま、このケースもDIVにonclickをつけて、イベントからエレメント、タグ名を取ってIMGなら実行、、と言う方法を使えば 全てのIMGタグにonclickを埋め込まなくても済んでしまいますけど。。

結局何をやるにしても『目的の操作対象』が必ず意識されてるわけです。 自分が扱うページで『不特定多数のタグ』を相手にする事はそれほど多いケースではありません。 『これしか手が無い』あるいは『これが最も有効』と言う場合に使いましょう。
コーディングを短くする『省略の美学』を設計者は好みます。 でも、コーディングが短い事とトータルの実行処理がスムーズである事は別の場合もあります。
ちょっとベタな方法でも実行処理が早い、無駄な負担をかけない事を美学とする考えもあります。

何故こんな事を書くかと言うと、
このメソッドで全てのタグをオブジェクトにして配列にすれば、for文で全要素チェックを行ってそこからIDやClassNameやその他アトリビュートなどをチェックして・・・と言う方法を使えば特定できるのは当然です。 でも、それは引き出しから1個の物を取り出す為に引き出しの中身を全部机の上に出して探して・・・と言う作業をしてるのと同じです。 せっかくgetElementById()の様にピンポイントでオブジェクトが取れる方法があるのですから、 引き出しをひっくり返すような事をしないのがスマート且つ速く処理が進みます。 机の中(id名やclass名や構造など)を最初から整理されている事も大事です。
逆に、引き出しをひっくり返して探した方がずっと便利な状況においては、積極的に使っていくべきです。

Object.getElementsByClassName()

これはドキュメント内から指定ClassNameで該当するものを抽出するメソッドです。

Object.getElementsByClassName(classname)

が、これはFireFox3からの実装になると思います。
IEも多分時期IEに実装してくるかもしれませんね。

現実的に考えるとクラス指定、つまりグループ分けしておいて そのグループ(個別要素の配列)をコントロールできる事は便利です。 が、対象のCSSの内容を変更するのであればdocument.StyleSheetsでセレクタを指定して値を指定すれば済む話です。 CSS設定との絡みなどを気にしながら使わないといけないクラス名で無理にグループ分けする必要はないです。

実装されていない現在(IE7、FF2)、このメソッドを実現する場合は、
前述の getElementsByTagName()で必要な範囲の指定タグ(または全部)をとる。

for文で各要素のクラス名をチェックして該当する物を配列化する。

同じクラス名の集合配列が出来上がる。

と言う方法があります。

同じクラスでも複数のタグにまたがる場合は複数のタグの配列を操作する必要があり、 タグをワイルドカードにした場合はあらゆるタグの配列を操作する必要が出てきます。
ドキュメントの大きさにもよりますが、全てのタグをfor文で全部調べてと言う方法は、 他に何も手てが無い場合や後付で仕方なく・・・と言う場合には使いますが、 最初から設計する場合は無駄な処理方法と言えます。

もしグループ化がどうしても必要でページ内で頻繁に使う可能性があるのであれば、 window.onloadのタイミングで配列を作ってしまっておくのが良いです。

結果的に無駄な処理を増やさない方法をID付けの時点で設計していくべきです。
自分の製作してるHPであれば、設計をきちんとしておく事で無駄な処理を省けます。
IDの付け方はプログラムの設計の最初の整理です。

getElementsByClassName()が実装されれば、無駄なループ処理がなくなりますから使い勝手はもちろん良くなりますので期待しています。


グループ化

これは、HTMLエレメントをグループ化する必要がある場合の方法論です。

■ アトリビュートをつけてしまう方法
前述のまだ未実装のクラス名からの対象オブジェクトの集合配列取得でも書きましたが、 クラス名をJavaScriptでそのまま利用しやすい状況なら良いのですが、そうでもない場合もあります。
或いは、そのクラス名の中で更にまた分類したい場合などもあります。

こういう場合は勝手にタグのアトリビュートを作ってしまう手があります。

<DIV id="div1" class="aaa" grp="1" > <DIV>

grpなどと言うアトリビュートは無いので無視されますから気にしない。
グループ名は配列で使いやすいように0からの数字にする。

window.onload = function(){ //オンロード直後処理
    //対象タグが決まっていればそれを指定、決まってなければワイルドカード
    var tags = document.body.getElementsByTagName("*");
    Grps = [];
    for(var i=0; i<tags.length; i++){
        var grp = tags[i].getAttribute('grp');
        if(grp !== undefined){
              if(typeof Grps[grp] == "undefined"){ Grps[grp] = []; }
              Grps[grp].push(tags[i]);
        }
    }
}
これでグローバル変数 Grps がグループ全体の配列になり、 各要素 Grp[0] 等のグループ名(数字)をindexとした要素がさらにそのグループに属するHTMLオブジェクトを格納してる2次元配列となります。

ある特定グループの何かを操作したい場合は
for(var i=0; i<Grop[グループ番号].length; i++ ){
Group[グループ番号][i].style・・・・
}
の様に操作できます。

これはこの方法を使った方が有益な場合に行う事であって、 前の方に書いたように全てのタグをチェックなんて方法はあまり推奨する方法ではありません。

window.onloadで作られた Grps と言う配列ですが、これは
最初からアトリビュートなどつけずに、JavaScript内で
Grp[0] = ['id','id','id','id','id','id'];
Grp[1] = ['id','id','id','id','id','id'];
Grp[2] = ['id','id','id','id','id','id'];
または
Grp = [['id','id','id','id','id','id'],['id','id','id','id','id','id'],・・・]
の様に手書きリストで配列を書いておくのと同じ事です。
手書き配列はより動的に取得できる方法の方が汎用性や見栄えとしてプログラムらしいですが、 静的なリストであれば、それをプログラムで取得するのは無駄な処理が増える事になります。 実際に動的に取得するかどうかは、そのページの状況、設計、管理方法によります。


■昔ながらのグループ化 (接頭語、接尾語)
これは最も?古くから使われている方法だと思います。
id や name で使う名前を最初から考えてつけます。 無計画な方法を後からカバーするより最初からしっかりプランを立てておく方法です。

<img src="" id="img1_1">
<img src="" id="img1_2">
<img src="" id="img1_3">
<img src="" id="img1_4">

<img src="" id="img2_1">
<img src="" id="img2_2">
<img src="" id="img2_3">
<img src="" id="img2_4">

最初からこうしておけば、グループ分けされてるのと同じ様に扱えます。 id や nameをつける時に、その場その場で好きな名前を付けていくのは無計画すぎますしね。
for(var i=1; i<5; i++ ){
document.getElementById('img1_' + i).style・・・・
}
最初からきちんと整理されていれば、必要な対象オブジェクトの数だけのループ処理で全てが済みます。 無駄の無い処理です。
調べる時もmatch()などで探しやすいパターン化したIDにしておく事は有効になります。
が、動的なプログラムや汎用性のあるプログラムを書く時はこれでは使いにくくなります。
その時の用途・目的などにあわせて臨機応変に。


行き当たりばったりでIDをつけたり、クラス名をつけたりしない事はJavaScriptにとっては大事です。 IDの付け方、クラス名の付け方、処理の仕方を工夫していけば、その時その時で最良の方法が見つかります。 前にも書いていますが、id、name、class名を整理整頓して付けていく事がプログラムの最初の段階でもあります。


専用ページから申し込むと
So-netより高い3万円CB

案ずるより産むが易し
使ってみれば疑問も解決

XREA+ (plus) 206円/月
( お試し7日間 )

CORE SERVER 428円/月
( お試し15日間 )

ロリポップ 270円/月
( お試し期間10日間 )

ヘテムル 1620円/月
( お試し期間15日間 )

さくら 129円/月
( お試し期間2週間 )

無駄な高額ドメイン管理料金払ってませんか?

バリュードメイン
ムームードメイン

お客さんに振込手数料を払わせていませんか?イーバンク銀行同士なら振込手数料無料。 オフィスで簡単振込み イーバンク銀行 ビジネス口座