第12回 発生したイベントの状態を保持・保存する6つのパターン – jQuery入門

2009 年 9 月 4 日 投稿者: naga3

仕事で少しjQueryを触ったのですが、結局jQuery(JavaScript)でやることのほとんどは、DOM要素へのユーザーのイベント(クリックやキー入力など)の状態を保持しておき、最終的にGETやPOSTでサーバアプリに値を送る、という感じだと思うのです。

そんなわけで、イベントの状態を保持する方法を6パターンほど考えました。

1.変化したCSSの値をそのままチェックする

何かイベントが起こった後というのはふつう、対象となるDOM要素の色が変わっていたり大きさが変わっていたりするので、その値を直接見るという、一番シンプルな方法です。以下に、テーブルの各セルをクリックするたびに背景色が黄色と白でトグルするサンプルを示します。


state_save1.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1.3");</script>

<script type="text/javascript">
$(function() {
    $('td').mousedown(function() {
        if ($(this).css('backgroundColor') == 'yellow') {
            $(this).css('backgroundColor', 'white');
        } else {
            $(this).css('backgroundColor', 'yellow');
        }
    });
});
</script>
<style type="text/css">
td {
    background-color: white;
    border: 1px solid black;
    padding: 8px;
    cursor: pointer;
}
</style>
</head>
<body>
<table>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td>6</td></tr>
<tr><td>7</td><td>8</td><td>9</td></tr>
</table>
</body>
</html>
CSSの背景色を直接チェックしています。シンプルでうまく行きそうですが、ひとつ問題があります。チェック部分を以下のように書き換えると・・・

state_save1b.html
・・・
    $('td').mousedown(function() {
        if ($(this).css('backgroundColor') == 'white') {
            $(this).css('backgroundColor', 'yellow');
        } else {
            $(this).css('backgroundColor', 'white');
        }
    });
・・・
Firefoxでは、一度目のクリックが反応しません。2度目からは動きます。最初にCSSで背景色をwhiteにすると値がRGB(255,255,255)になるのが原因のようです。このようにCSSの値を直接チェックするのは危険なものがあります。

2.クラスの追加・削除(トグル)

2番目の方法は、イベントの状態を各DOM要素にクラスを追加・削除して管理する方法です。jQueryはクラスを追加・削除する便利なメソッドがいくつか用意されています。以下にスクリプト部分を示します。
state_save2.html
・・・
<script type="text/javascript">
$(function() {
    $('td').mousedown(function() {
        $(this).toggleClass('selected');
    });
});
</script>
<style type="text/css">
td {
    background-color: white;
    border: 1px solid black;
    padding: 8px;
    cursor: pointer;
}
td.selected {
    background-color: yellow;
}
</style>
・・・
ずいぶんシンプルになりました。toggleClassによってselectedクラスがあれば消し、無ければ追加しています。クラスをトグルすると同時に色も変化するので直感的な方法だと思います。

3.オリジナルの属性値として保存する

簡単なものならば2番目の方法で十分なのですが、保持する情報が複雑になってくると別の方法を考えなければなりません。3番目は、タグに値を保存する専用の属性を用意する方法です。以下にサンプルを示します。
state_save3.html
・・・
$(function() {
    $('td').mousedown(function() {
        if ($(this).attr('color') == 'yellow') {
            $(this).attr('color', 'white');
        } else {
            $(this).attr('color', 'yellow');
        }
        $(this).css('backgroundColor', $(this).attr('color'));
    });
});
</script>
<style type="text/css">
td {
    background-color: white;
    border: 1px solid black;
    padding: 8px;
    cursor: pointer;
}
</style>
・・・
「color」というタグの属性を用意してそこに現在の色を保存しています。一応動きますが、勝手に独自の属性を増やしていいのか分かりません。やっちゃダメかも。

4.値を保存する場所を外に出す

規模が大きくなってきたら、値を保持する領域は外出しの配列などにしたほうが、デザインとの分離が出来て良いと思います。以下にスクリプト部分を示します。
state_save4.html
・・・
<script type="text/javascript">

var colors = [];

$(function() {
    $('td').mousedown(function() {
        var n = this.id.split('_')[1] - 1;
        if (colors[n] == 'yellow') {
            colors[n] = 'white';
        } else {
            colors[n] = 'yellow';
        }
        $(this).css('backgroundColor', colors[n]);
    });
});
</script>
<style type="text/css">
td {
    background-color: white;
    border: 1px solid black;
    padding: 8px;
    cursor: pointer;
}
</style>
</head>
<body>
<table>
<tr><td id="td_1">1</td><td id="td_2">2</td><td id="td_3">3</td></tr>
<tr><td id="td_4">4</td><td id="td_5">5</td><td id="td_6">6</td></tr>
<tr><td id="td_7">7</td><td id="td_8">8</td><td id="td_9">9</td></tr>
</table>
</body>
</html>
テーブルのそれぞれのセルにIDを付けているのがポイントです。このID値によってクリックされた要素がどの要素か判別し、グローバル配列colorsに状態を保持します。

5.DOM要素のプロパティに保持する

上記4.の方法は汎用的に使えますが、管理する情報が多くなるのがデメリットです。そもそもDOM要素はJavaScriptのオブジェクトなので、そのプロパティとして情報を保持してしまえばシンプルで楽です。
state_save5.html
・・・
<script type="text/javascript">
$(function() {
    $('td').mousedown(function() {
        if (this.color == 'yellow') this.color = 'white';
        else this.color = 'yellow';
        $(this).css('backgroundColor', this.color);
    });
});
</script>
<style type="text/css">
td {
    background-color: white;
    border: 1px solid black;
    padding: 8px;
    cursor: pointer;
}
</style>
・・・

6.dataメソッドで保持する

上記4.の方法はシンプルなのですが、オブジェクトのプロパティとして既に定義されているものと被る危険性があります。そこでjQueryオブジェクトのdataメソッドというものを使うと、オブジェクトに独自のデータをいくらでも追加することができます。以下にサンプルを示します。
state_save6.html
・・・
<script type="text/javascript">
$(function() {
    $('td').mousedown(function() {
        if ($(this).data('color') == 'yellow') {
            $(this).data('color', 'white');
        } else {
            $(this).data('color', 'yellow');
        }
        $(this).css('backgroundColor', $(this).data('color'));
    });
});
</script>
<style type="text/css">
td {
    background-color: white;
    border: 1px solid black;
    padding: 8px;
    cursor: pointer;
}
</style>
・・・
jQueryっぽく、直感的に安全に使えると思います。

まとめ

上に示した5つのパターンはどれも帯に短し襷に長し、という感じでメリットとデメリットがあり、決定版というものはありません。自分が仕事でjQueryを使ったときは、データは外出しのオブジェクトとして管理しておき、タグにはdataメソッドを付けて関連付けしました。何かほかに良い方法があればぜひコメントで教えてください。

この記事へのトラックバックURL

コメントをどうぞ