gijyutsu-keisan.com

コラム

%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9%E3%83%BB%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC

作成日:20210225  テーマ1:%E6%83%85%E5%A0%B1%E7%B3%BB  テーマ2:Web%E7%B3%BB  テーマ3:javascript

javascriptで多段のチェックボックスメニューを作ってみたので記録しておく。
メニューはこんな感じ。


checkboxのidとnameに法則性を持たせることが肝の模様。
サンプルファイルは以下の通り。
では、ソースについて。

(1)html

checkbox部分のみ表示すると、
<div id="divchk">
  <ul>
    <li><label><input id="chk" name="chkall" onclick="ChkHideShowChg(this.id);" type="checkbox">すべて選択/すべて解除</label>
      <ul>
        <li><label><input id="chk-0" name="chk" onclick="ChkHideShowChg(this.id);" type="checkbox" value="A">A</label></li>
        <li><label><input id="chk-1" name="chk" onclick="ChkHideShowChg(this.id);" type="checkbox" value="B">B</label></li>
        <li><label><input id="chk-2" name="chk" onclick="ChkHideShowChg(this.id);" type="checkbox" value="C">C</label>
          <ul>
            <li><label><input id="chk-2-0" name="chk-2" onclick="ChkHideShowChg(this.id);" type="checkbox" value="C1">C1</label></li>
            <li><label><input id="chk-2-1" name="chk-2" onclick="ChkHideShowChg(this.id);" type="checkbox" value="C2">C2</label>
              <ul>
                <li><label><input id="chk-2-1-0" name="chk-2-1" onclick="ChkHideShowChg(this.id);" type="checkbox" value="C21">C21</label></li>
                <li><label><input id="chk-2-1-1" name="chk-2-1" onclick="ChkHideShowChg(this.id);" type="checkbox" value="C22">C22</label></li>
              </ul>
            </li>
          </ul>
        <li><label><input id="chk-3" name="chk" onclick="ChkHideShowChg(this.id);" type="checkbox" value="D">D</label></li>
        <li><label><input id="chk-4" name="chk" onclick="ChkHideShowChg(this.id);" type="checkbox" value="E">E</label>
          <ul>
            <li><label><input id="chk-4-0" name="chk-4" onclick="ChkHideShowChg(this.id);" type="checkbox" value="E1">E1</label>
              <ul>
                <li><label><input id="chk-4-0-0" name="chk-4-0" onclick="ChkHideShowChg(this.id);" type="checkbox" value="E11">E11</label></li>
                <li><label><input id="chk-4-0-1" name="chk-4-0" onclick="ChkHideShowChg(this.id);" type="checkbox" value="E12">E12</label></li>
              </ul>
            </li>
            <li><label><input id="chk-4-1" name="chk-4" onclick="ChkHideShowChg(this.id);" type="checkbox" value="E2">E2</label>
              <ul>
                <li><label><input id="chk-4-1-0" name="chk-4-1" onclick="ChkHideShowChg(this.id);" type="checkbox" value="E21">E21</label></li>
                <li><label><input id="chk-4-1-1" name="chk-4-1" onclick="ChkHideShowChg(this.id);" type="checkbox" value="E22">E22</label></li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</div>

ここで、nameはidの-以降をとったものとしている(id="chk-0"ならname="chk")。
こうすることでscriptはいっきに書きやすくなる(と思っている)。 ちなみに、すべてのcheckboxに対して同じ関数表記"ChkHideShowChg(this.id)"で対応できる。

(2)javascript

/***********************************************************

checkbox操作時の処理

***********************************************************/
function ChkHideShowChg(ID, Lvbtm) {
  
  //最下層の設定
  if (Lvbtm==undefined) {
    Lvbtm=3;
  }
  
  //下の階層処理
  ChkHideShowChgLow(ID, Lvbtm);
  
  //上の階層処理
  ChkHideShowChgUp(ID);
}

/* ===============================================
下の階層処理
=============================================== */
function ChkHideShowChgLow(ID, Lvbtm) {
  
  var cnt1, cnt2, cnt3;
  var splitary=ID.split("-");
  
  if (splitary.length<=Lvbtm) {
    
    //clickしたboxのcheck状態取得
    var chkflag=document.getElementById(ID).checked;
    
    //下の階層のチェックをすべてchkflagに合わせる
    var elements=document.getElementsByName(ID);
    for (cnt1=0; cnt1<elements.length; cnt1++) {
      elements[cnt1].checked=chkflag;
      
      //ここだけ再帰処理
      ChkHideShowChgLow(ID+"-"+cnt1, Lvbtm);
    }
  }
}

/* ===============================================
上の階層処理
=============================================== */
function ChkHideShowChgUp(ID) {
  
  var cnt1, cnt2, cnt3;
  var splitary=ID.split("-");  //-の数で階層を判別
  
  for (cnt1=splitary.length-1; cnt1>0; cnt1--) {
    
    //階層に応じたname
    name="";
    for (cnt2=1; cnt2<cnt1; cnt2++) {
      name+="-";
      name+=splitary[cnt2];
    }
    name=splitary[0]+name;
    
    //checked=falseのチェック
    var elements=document.getElementsByName(name);
    for (cnt2=0; cnt2<elements.length; cnt2++) {
      if (elements[cnt2].checked==false) {
        break;
      }
    }
    
    //falseが1個でもあったらチェックを外す
    if (cnt2==elements.length) {
      document.getElementById(name).checked=true;
    } else {
      document.getElementById(name).checked=false;
    }
  }
}
関数の引数はIDのみ。nameはIDを"-"でsplitして再構築できるのと、"-"の数で階層を判別できるので便利。
下の階層に向かっての処理は下図のように行われ、Eの子要素はEと同じ状態(チェック入れれば全部入る)になるので、再帰的に処理してやればよい。
上の階層に向かっての処理は、同一階層に一つでもチェックの外れているものがあれば、それ以降の親階層もすべてチェックを外す。 ざっくりと次のような法則性にもとづいて処理を行えばよい。

(3)css

リストの体裁を整えるだけ。本質的ではない。
* {
  margin      : 0px;
  padding      : 0px;
  letter-spacing  : 0.1em;
  line-height    : 1.5em;
}

#divchk ul {
  list-style: none;
  margin-left: 20px;
}
  #divchk ul li {
    clear: both;
    float: left;
    margin-top: 3px;
  }

コラムページトップへ

参考文献