jQuery / メソッド / .toggle() - 表示と非表示を切り替える

jQueryの.toggle()は表示中の各要素を隠し、非表示なら表示します。.toggle(true)は表示、.toggle(false)は非表示の指定で、.toggle(800)のような時間指定ではアニメーションになります。反転と既知の状態への指定を使い分けます。

即時反転・状態指定・効果の違い

.toggle()の仕様では引数なしならdisplayを即時に切り替えます。Alpha表示・Beta非表示なら一度でAlpha非表示・Beta表示です。集合全体を同じ状態へそろえる意味ではありません。

呼び出し 動作 選ぶ条件
.toggle() 各状態を反転 現在の反対へ
.toggle(true)・.toggle(false) 表示・非表示を指定 希望状態が既知
.toggle(800) 800msで変化 寸法と不透明度を変える
.toggle({ duration: 0, complete: 関数 }) 時間0の効果経路 即時完了と完了処理

時間付き効果は幅・高さ・不透明度を変え、非表示完了時のdisplay:noneで配置空間もなくなります。800msは0.8秒で、大きい値ほど遅くなります。真偽値falseと数値0は別の引数です。隠すだけで入力値などDOM(Document Object Model、文書オブジェクトモデル)の状態を削除しません。

二つのパネルで試す完全な例

全コードをUTF-8のtoggle-demo.htmlに保存し、ブラウザーで開きます。インターネットでコンテンツ配信ネットワーク(CDN)の公式jQuery完全版4.0.0を読みます。時間付き効果にはeffectsが必要なためslimに変えません。操作とConsole例を3.7.1・4.0.0で実行しました。

Alphaはflex表示、Betaは初期非表示です。操作部はパネル外にあります。即時・800ms・200ms・0msから選び、効果中の追加要求はbusyで無視します。システムの動きを減らす設定では時間0を使います。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Toggle each panel visibility</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
    button, select, input { font: inherit; margin: 4px; max-width: 100%; box-sizing: border-box; }
    .panel { padding: 12px; margin: 10px 0; border: 1px solid teal; background: #edf9f6; }
    #alpha { display: flex; flex-wrap: wrap; align-items: center; }
    #beta { display: none; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>Toggle independently or set a known state</h1>
  <label for="mode">Mode:</label>
  <select id="mode"><option value="instant">No arguments</option><option value="800">800ms</option><option value="200">200ms</option><option value="0">0ms</option></select>
  <button type="button" id="toggle">Toggle each</button>
  <button type="button" id="show">Show both</button>
  <button type="button" id="hide">Hide both</button>
  <button type="button" id="reset">Reset</button>
  <div id="panels">
    <div class="panel" id="alpha">Alpha <input aria-label="Alpha note" value="Keep this note"></div>
    <div class="panel" id="beta">Beta panel</div>
  </div>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      const $panels = $("#panels > .panel");
      let busy = false, completed = 0;
      function report() {
        const visible = $panels.filter(":visible").map(function () { return this.id; }).get();
        $("#result").text(`visible=${visible.join(",") || "(none)"}\ncompleted=${completed}\nbusy=${busy}\nDOM panels=${$panels.length}`);
      }
      function settle() { $panels.stop(true, true); busy = false; completed = 0; }
      $("#toggle").on("click", function () {
        if (busy) return;
        completed = 0;
        const mode = $("#mode").val();
        if (mode === "instant") { $panels.toggle(); report(); return; }
        if (!$panels.length) { report(); return; }
        busy = true; report();
        const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
        $panels.toggle({ duration: reduced ? 0 : Number(mode), complete: function () {
          completed++;
          if (completed === $panels.length) busy = false;
          report();
        } });
      });
      $("#show").on("click", function () { settle(); $panels.toggle(true); report(); });
      $("#hide").on("click", function () { settle(); $panels.toggle(false); report(); });
      $("#reset").on("click", function () {
        settle(); $("#alpha").toggle(true); $("#beta").toggle(false);
        $("#alpha input").val("Keep this note"); $("#mode").val("instant"); report();
      });
      report();
    });
  </script>
</body>
</html>

初めはAlphaだけ見えますが、両パネルとも文書に残ります。

visible=alpha
completed=0
busy=false
DOM panels=2
  1. No argumentsでToggle eachを押すとBetaだけ表示され、completedは0です。再度でAlphaに戻ります。
  2. Alphaの入力を編集し、隠して戻すと編集値が残ります。flexの復元も確認します。
  3. 800msの完了後はvisible=beta、completed=2、busy=falseです。完了関数は全体に一度でなくパネルごとに実行します。
  4. 効果中の連打は無視して待ち行列を増やしません。200msとはReset後の同じ条件で比較します。
  5. Show bothは両方表示、Hide bothは両方非表示です。繰り返しても指定状態のままです。
  6. Resetは進行中効果を整理しAlpha表示・Beta非表示、入力既定値とモードを戻します。値変更は非表示のためでなく明示的.val()です。

0msは引数なしと見た目が似てもcompleteが各パネルで実行されcompleted=2です。動きを減らす設定も同じ経路を使い、サイト全体の効果設定を変えません。アニメーション中の:visibleを最終状態と決めつけず、完了後に確認します。

真偽値と実行中の初期化

条件で表示を決めるなら実際の真偽値を渡します。trueを二度渡しても隠れません。同ページの開発者ツールConsoleで次を実行し、一時要素二つで確認後に削除します。

const $holder = $('<div><p>A</p><p>B</p></div>').appendTo("body");
const $items = $holder.find("p");
$items.toggle(false);
$items.toggle(false);
console.log(`hide twice visible=${$items.filter(":visible").length}`);
$items.toggle(true);
$items.toggle(true);
console.log(`show twice visible=${$items.filter(":visible").length}`);
console.log(`DOM count=${$items.length}`);
$holder.remove();
hide twice visible=0
show twice visible=2
DOM count=2

効果中の状態指定は待ち行列と内部状態を考慮します。settle()は.stop(true, true)で待機を消し現在効果を完了してからbusy・completedを初期化します。二つ目のtrueで完了処理が即時実行されるため、カウンター初期化はstopの後です。

Resetはその後既知の状態を指定します。途中寸法で停止する動作と最終地点まで完了する動作は違います。実行中Reset直後に引数なし反転を押してもAlphaからBetaへ正しく変わることまで確認しました。別の連打方針なら無視・待機・現在効果の完了から意図を先に決めます。

見えない・効果が違うとき

まず選択子、.length、jQuery読込を確認します。祖先がdisplay:noneなら子の.toggle(true)だけでは見えない場合があります。visibility:hidden・opacity:0とも区別します。toggleはあらゆる非表示原因を解除するメソッドではありません。

即時終了するなら時間、動きを減らす設定、読込版を確認します。不透明度だけか高さだけかも区別して効果を選びます。途中寸法を繰り返し読み永続スタイルへ書くと復元に影響するため、目的なく混ぜません。

フォーカスのある領域を隠すなら再操作部とフォーカス移動も設計します。例は操作部を外に残しますが、フォーカス復元や展開通知をすべて実装した部品ではありません。表示切り替えだけで対話操作全体が完成したとは判断しません。