2008年9月4日木曜日

JavaScript でキー入力に応じて HTML の要素の値とスタイルを変化させる

JavaScript でブラウザのウィンドウのリサイズに合わせて HTML の要素の値を更新 のつづき

1. JavaScript によるHTML要素の動的な変化

JavaScript を用いて、HTML の要素を動的に変化させたい。

下図に示すように、左上のフォームのテキストフィールドに、ユーザがキーボードで入力したのに応じて、右下のフォームのフィールドの数値をインクリメントする。

同時にフィールドの下にある HTML の要素の幅を広げる。

080904-001-vert

キーの入力に対応させるには、keydown, keypress, keyup のイベントハンドラを利用する。

 

ソースコード
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional/EN">
<html>
  <head>
    <title>increment</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <style type="text/css">
    <!--
    #frm2{ text-align: center;}
    #frm2 .bar{ margin: 0px auto; }
    .bar { width: 0px; }
    #abar{ background-color: #fbb;}
    #bbar{ background-color: #bfb;}
    #cbar{ background-color: #bbf; }
    
    -->
    </style>

    <script type="text/javascript">
    <!--
    var counter = 0
    /* 指定された名前のフォームの要素の値をインクリメントする */
    function increment(name){
        stmt = 'document.forms["frm2"].' + name + '.value = counter++;';
        eval(stmt);
        incWidth(name + "bar");
    }
    
    /* 指定された id の要素の幅を広げる */
    function incWidth(id){
        width = document.getElementById(id).offsetWidth;
        width++;
        document.getElementById(id).style.width = width + 'px';
    }
    //-->
    </script>

  </head>
  <body onresize="increment()">

    <form name="frm">
        <!-- 文字を入力するフィールド -->
        <input type="text"
                    onkeydown ="increment('a')"
                    onkeypress="increment('b')"
                    onkeyup   ="increment('c')" />
    </form>
    
    <!-- 上のフィールドに入力された文字数に応じて表示が変化する -->
    <form id="frm2" name="frm2">
        <input type="text" name="a" />
            <div class="bar" id="abar">&nbsp;</div>
        <input type="text" name="b" />
            <div class="bar" id="bbar">&nbsp;</div>
        <input type="text" name="c" />
            <div class="bar" id="cbar">&nbsp;</div>
    </form>

  </body>
</html>

 

2. HTML 要素の幅を取得する

JavaScript で HTML の要素の幅を取得する方法は、

を参照。以下で述べる DOM の一種。

 

3. eval() 関数で実行時に評価する

eval() 関数は、eval – MDC によると、

Evaluates a string of JavaScript code without reference to a particular object.

ただし、EfficientJavaScript - Dev.Opera - 効率的な JavaScript の「eval と with は隔離しよう」の説明には、次のように述べられている。

これらの構文は性能への影響がとても大きいため, 利用は最小限に留めたい.

追記(2008.9.4) : 上記の eval() 関数を使っている部分は、 JavaScripter さんに教えていただいた書き方をすれば必要なくなる。

追記 (2009.10.3): JavaScript: The Good Parts (p129) 「付録B 悪いパーツ, B.3 eval」の「添え字記法」を参照。

 

4. HTML Form Element

DOM により要素にアクセスする

HTML の要素を取得するには、

document.getElementById(“id名”)

のように、 DOM で定義されているメソッドを経由して取得する。

What is the Document Object Model? によると、

The Document Object Model (DOM) is an application programming interface (API) for valid HTML and well-formed XML documents.

DOM とは、キチンとした形の文書に対して、その要素にアクセスするための API を定義したもの。

 

forms により要素にアクセスする

HTML のフォームの要素にアクセスするのに 、

document.forms[0].名前

と書くことができる。これは先ほどの要素へアクセスする方法とは違って見える。

Gecko DOM Referenceelement によると、

While these interfaces are generally shared by most HTML and XML elements, there are more specialized interfaces for particular objects listed in the DOM HTML Specification—for example the HTML Table Element and HTML Form Element interfaces.

getElementById() は一般的な DOM であるのに対して、document.forms[] は HTML に特有な方法。

forms とは、Document Object Model HTML によると、

forms of type HTMLCollection, readonly
A collection of all the forms of a document.

HTMLCollection とは、1.5. Objects related to HTML documents によると、

An HTMLDocument is the root of the HTML hierarchy and holds the entire content. Besides providing access to the hierarchy, it also provides some convenience methods for accessing certain sets of information from the document.

つまり、form は要素にアクセスしやすくするために定義されている。

以下の中で forms が定義されている。

Firebug の DOM タブにおいて document を表示させると、上記に定義されているものが表示される。

080904-004-horz

Firebug の表示は長くて、まともに見たことがなかったけれど、この際チェックしておこう。 (@_@;)

2コメント:

javascripter さんのコメント...

stmt = 'document.forms["frm2"].' + name + '.value = counter++;';
eval(stmt);
の部分を、
document.forms["frm2"][name].value = counter++;
にすれば、evalを使う必要がなくなります。

子馬 さんのコメント...

javascripter さんありがとうございます。 eval() を使わない方法はないのかな(?)と思ってたので参考になりました。

そういえば、オブジェクトのプロパティに値を設定するように書く書き方は、ハッシュにキーと値を追加することと同じことであることを忘れていました。 (+_+)

えーと、ということは、以下のようなハッシュがあった場合、

var obj = {'a1':{'b1':{'c1':'hoge'}, 'b2':'piyo'}, 'a2':{'b1':'fuga'}}

obj['a1']['b1']['c1']
obj['a1']['b1'].c1
obj['a1'].b1.c1
obj['a1'].b1.c1
obj.a1.b1.c1

上記は全て同じということと同じだったんですね。