JavaScript による入力項目無効設定の高速化 - その2

コメントにてご指摘を受けたように、下記例のように単に入力項目が多いというだけでは、無効化の処理は遅くはならないようです。

<!-- tag.disabled = true; で遅くならない例 -->
<html>
  <body>
    <form>
      <input type="text"/>
      <input type="text"/>
      <input type="text"/>
         :
         :
    </form>
  </body>
</html>

しかし、下記例のように、テーブルタグ内に入力項目を配置すると、途端に遅くなります。

<!-- tag.disabled = true; で遅くなる例 -->
<html>
  <body>
    <form>
      <table>
        <tr>
          <td>
            <input type="text"/>
            <input type="text"/>
            <input type="text"/>
            <input type="text"/>
          </td>
        </tr>
         :
         :
      </table>
    </form>
  </body>
</html>

また、すべての入力項目が遅くなるわけではなく、type="text"、type="password"、type="file"についてのみ、遅くなるようです*1

先日のエントリでは、これらの項目に対して、DOM によるノードの複製と入れ替えを利用することで、無効化処理を高速化することを記述しました。が、バグがありました(汗。
IE固有の問題なのか、<input type="checkbox">タグ、<input type="radio">タグ、<select>タグに対して Node#cloneNode(true) を使用して、ノードの複製を作成した場合、選択状態が正しく複製されません。このため、チェックボックスラジオボタンの選択が解除される、ドロップダウンリスト選択が変更されるなどの不具合が発生します。


これらの問題を回避するために、ノードの複製以外で高速化を行ないました。
先日のれー氏のコメント(レンダリングによる性能劣化)をヒントに、以下のようなコードによる無効化処理を行ないました。

function setEnabled(enabled) {
  var tags = document.all.tags("input");
  var length = tags.length; // drry 氏の指摘により改善
  for (var i=0; i<length; i++) {
    var tag = tags[i];
    var display = tag.style.display;
    tag.style.display = "none";
    tag.disabled = !enabled;
    tag.style.display = display;
  }
}

入力項目を無効に設定する前に、項目を非表示にしておき、無効設定後に元通り表示状態にもどします。
たったコレだけのことで、入力項目がテーブル内に配置されていても、ほぼ一瞬で処理が終わるようになりました。

項目が表示状態のままであろうが、無効に設定後に表示状態に変更されようが、差は無いような気もする*2のですが、なぜこんなにも速度に差がでるのか不思議です。

*1:テキストの1行入力用コントロールとして表示されるものが関係している模様

*2:1個ずつ [表示→非表示→無効設定→表示] しているので。一気に表示、非表示を切り替えるとかならまだ分かるのですが・・・

おまけ - JavaScript による DOM 操作 - 属性の取得

IE のバグ?を確認するコードです。記憶を頼りに適当に書いているので、動かないかも。

<html>
  <head>
    <script>
      function test() {
        var element = document.getElementById("w");
        alert("element.getAttribute(\"checked\"): "+element.getAttribute("checked"));

        var attributes = element.attributes;
        var attributesStr = "";
        for (var i=0; i<attributes.length; i++) {
          var attr = attributes.item(i);
          attributesStr += attr.nodeName + "=" + attr.nodeValue+" ";
        }
        alert("attributes: "+attributesStr);
      }
    </script>
  </head>
  <body>
    <button onclick="test();">テスト</button>
    <form>
      <input type="checkbox" id="w" value="ai"/>復帰待ち
    </form>
  </body>
</html>

上記 HTML を表示し、チェックボックスにチェックした後に [テスト] ボタンを押下すると、getAttribute("checked") の結果は true が取得されるにもかかわらず、attributes プロパティによって、属性値を列挙した場合は、"CHECKED" 属性*1の値は false になっています。
この辺りが、 Node#cloneNode(true) で完全に複製を作成してくれないことと、関係しているのかと思います。

*1:checked 属性ではなく、CHECKED 属性です

同一ページ内でポップアップウィンドウを開くJavascriptライブラリ

これは便利そうです。もう少し早めに知っていれば、今回のプロジェクトで使ってたかもしれません・・・

2/14 は・・・

今年の戦利品・・・ではなく、作成物

右の写真は、今年の戦利品・・・ではなく、作成物です。
毎年自分で作って、彼女にあげています(汗)*1
上に乗っているのは、オレンジ皮の千切りを砂糖水で煮た物・・・になるはずだったのですが、防カビ剤などが怖いので、国産のいよかん皮です(w


調子にのって乗せすぎてしまいました。この皮の下には、いよかんのふさが綺麗に並んでいるのですが・・・見えないですね _| ̄|○

ココアスポンジ*2を3枚にスライスし、その間にいよかんの実を混ぜたカスタードクリームをはさんでいます。
周りに塗られているのは、チョコクリームです。
このあと、オレンジ皮の部分を、レモン汁といよかん汁を混ぜたゼリーで覆いました。


実に、1年ぶりのケーキ作りだったので、かなり手際が悪く、疲れました・・・(;´ρ`) グッタリ

*1:彼女からは、ペンギンチョコの乗った、バナナ+チョコクリームのパイをもらいました。( ゚Д゚)ウマー

*2:もちろん、スポンジも自分で焼いています。今回は別立ての水入りスポンジです。