Javascriptでdivを非表示および表示するためのより短く簡潔な方法はありますか?

受付中 プログラミング
2024-12-24
小次郎又三郎
「display:none;」で始まる約20divのダッシュボードを作成しています。 サイドバーの.onClick()を使用すると、特定のdivが表示され、他のすべてのdivは非表示になります。私は各divの関数を作成するという古典的なソリューションを使用しましたが、非常に長く、コードは混乱しているように見えます。 Javascriptでこれを達成するためのよりクリーンな方法はありますか? これが私のコードです:
        function presale() {
          var x = document.getElementById("presale");
          var y = document.getElementById("claim");
          var z = document.getElementById("stake");
          if (x.style.display === "grid") {
            x.style.display = "none";
          } else {
            x.style.display = "grid";
            y.style.display = "none";
            z.style.display = "none";
          }
        }
        
        function claim() {
          var x = document.getElementById("presale");
          var y = document.getElementById("claim");
          var z = document.getElementById("stake");
          if (y.style.display === "grid") {
            y.style.display = "none";
          } else {
            x.style.display = "none";
            y.style.display = "grid";
            z.style.display = "none";
          }
        }
        
        function stake() {
          var x = document.getElementById("presale");
          var y = document.getElementById("claim");
          var z = document.getElementById("stake");
          if (z.style.display === "grid") {
            z.style.display = "none";
          } else {
            x.style.display = "none";
            y.style.display = "none";
            z.style.display = "grid";
          }
        }
        
        *,
        html {
          color: #fff;
          background-color: black;
        }
        
        #presale,
        #claim,
        #stake
        /* Here I have many other divs like below */
        
        {
          display: none;
        }
        
        <!DOCTYPE html>
        <html lang="en">
        
        <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
          <link rel="stylesheet" href="MOD.CSS">
          <script src="main2.js"></script>
          <title>Base Template</title>
        </head>
        
        <body>
          <div>
            <ul>
              <!-- Here I have other 20 options like the above -->
              <li onclick="presale()">Presale</li>
              <li onclick="claim()">Claim</li>
              <li onclick="stake()">Stake</li>
              <!-- Here I have other 20 options like the above -->
            </ul>
            <div id="presale">
              <h1>Presale</h1>
            </div>
            <div id="claim">
              <h1>Claim</h1>
            </div>
            <div id="stake">
              <h1>Stake</h1>
            </div>
          </div>
        </body>
        
        </html>
        
関数を作成し、各divに対して同じことを何度も繰り返す必要なしにこれを行うためのより良い方法はありますか?
回答一覧
ReactやVueなどのフロントエンドフレームワークを使用している場合は、データバインディングを使用してそれを行うことができます。
小次郎又三郎
フレームワークは、あらゆる小さな問題の万能薬ではありません。
小次郎又三郎
@Andy私は同意しませんが、フレームワークはこれ(およびそれに続く他の避けられない質問)に対処します。また...フレームワークには通常、何かを行うための「正しい」方法があります。これらの答えは必然的にJavaScriptで自由に使えるようになります。
小次郎又三郎
しかし、React / Angle / Vueのようなものを学習するための時間の費用は、これらの回答のほとんどが示しているように、データ属性の使用方法を理解することと比較すると見劣りします。
小次郎又三郎
ここに、バニラJavascriptソリューションが表示されます。 contentdivはデフォルトで非表示になっています。 要素をクリックすると、対応data-idするクラスが取得されshowます。
        window.onload = function () {
        
          document.querySelectorAll('#nav li').forEach((elements) => {
            elements.addEventListener('click', (el) => {
              document.querySelectorAll('.content').forEach((item) => {
                // hide all
                item.classList.remove('show');
              });
              // show one
              document.getElementById(el.target.getAttribute('data-id')).classList.add('show');
            });
          });
        
        };
        
        .content {
          display: none;
        }
        .show {
          display: block;
        }
        
        <ul id="nav">
          <li data-id="presale">Presale</li>
          <li data-id="claim">Claim</li>
          <li data-id="stake">Stake</li>
        </ul>
        <div id="presale" class="content">
          <h1>Presale</h1>
        </div>
        <div id="claim" class="content">
          <h1>Claim</h1>
        </div>
        <div id="stake" class="content">
          <h1>Stake</h1>
        </div>
        
小次郎又三郎
JSはまったく必要ありません。アンカーを使用#idして、ハイパーリファレンスとして使用できます。:target次に、 -selectorを使用して、CSSを介して要素を表示できます。
        *,
        html {
          color: #fff;
          background-color: black;
        }
        
        .d-none
        /* Here I have many other divs like below */
        
        {
          display: none;
        }
        
        div:target {
          display: grid;
        }
        
        <!DOCTYPE html>
        <html lang="en">
        
        <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
          <link rel="stylesheet" href="MOD.CSS">
          <script src="main2.js"></script>
          <title>Base Template</title>
        </head>
        
        <body>
          <div>
            <ul>
              <!-- Here I have other 20 options like the above -->
              <li><a href ="#presale">Presale</a></li>
              <li><a href ="#claim">Claim</a></li>
              <li><a href ="#stake">Stake</a></li>
              <!-- Here I have other 20 options like the above -->
            </ul>
            <div id="presale" class="d-none">
              <h1>Presale</h1>
            </div>
            <div id="claim" class="d-none">
              <h1>Claim</h1>
            </div>
            <div id="stake" class="d-none">
              <h1>Stake</h1>
            </div>
          </div>
        </body>
        
        </html>
        
小次郎又三郎
私が今まで見た中で最も短い「js-solution」。
小次郎又三郎
確かに良い解決策です!しかし、要素の選択を解除する可能性を維持できますか?
小次郎又三郎
スマートで違う。+1ですが、本番環境では使用しません。
小次郎又三郎
jsなしで現在の<li>要素を強調表示することは可能ですか?
小次郎又三郎
はいradio-buttons、アンカーを使用してラップする場合は、 -selectorlabelsを使用してラベルを強調表示できます。:checked
小次郎又三郎
1 データ属性とクラスリストトグルを使用したこのようなものも機能するはずです。 一般的なCSSセレクターを使用して個々のセクションを非表示/表示することにより、コード(およびCSS)を最小化することを検討します。これにより、次の人のスケーラビリティと保守性も容易になります。 これには、JavaScriptで設定された任意のインラインスタイルではなく、CSSを使用してスタイリングを100%制御できるという追加の利点があります。 別のセクションを追加することも簡単です。 IDを使用して新しいセクションを追加します(例awesome-section) 。 data-toggle-sectionIDを値として持つ属性を持つナビゲーションエントリを追加します<li data-toggle-section="awesome-section">Awesome Section</li> 利益 また、イベントリスナーはセレクターを使用してバインドされるため、nav要素自体の使用に制限されません。[data-toggle-section]つまり、正しい値を持つ属性があれば、基本的にすべてのセクションを表示または非表示にできます。
        const buttons = Array.from(document.querySelectorAll("[data-toggle-section]"));
        const sections = buttons.map(element => {
            return document.getElementById(element.dataset.toggleSection)
        });
        
        buttons.forEach(element => {
            element.addEventListener('click', event => {
                const selected = element.dataset.toggleSection;
        
                sections.forEach(section => {
                    if(section.id === selected) {
                        section.classList.toggle('shown');
                    } else {
                        section.classList.remove('shown');
                    }
                })
            });
        });
        
        *,
        html {
            color: #fff;
            background-color: black;
        }
        
        .option-section {
            display: none;
        }
        
        .option-section.shown {
            display: grid;
        }
        
        <div>
            <ul>
                <!-- Here I have other 20 options like the above -->
                <li data-toggle-section="presale">Presale</li>
                <li data-toggle-section="claim">Claim</li>
                <li data-toggle-section="stake">Stake</li>
                <!-- Here I have other 20 options like the above -->
            </ul>
            <div id="presale" class="option-section">
                <h1>Presale</h1>
            </div>
            <div id="claim" class="option-section">
                <h1>Claim</h1>
            </div>
            <div id="stake" class="option-section">
                <h1>Stake</h1>
            </div>
        </div>
        
小次郎又三郎
マイナーな改善点の1つは、セレクターを使用して、表示/非表示にするのではなく、どちらを表示するかを決定することです。sections.forEach
小次郎又三郎
これは大きな改善ではなく、少量のメモリを除けば実際の改善になるかどうかさえわかりません。各イベントにdocument.querySelectorAllを使用すると、CPUが少し多く使用されます。これは、改善というよりもトレードオフの方が多いと思います。
小次郎又三郎
        const elems = ["presale", "claim", "stake"];
        
        function toggle(elem) {
            elems.map(i => {
                let el = document.getElementById(i);
                if (el.style.display === "grid") {
                    el.style.display = "none";
                } else {
                    el.style.display = "grid";
                }
            })
        }
        
そしてhtmlで要素名をパラメータとして追加するので、これを置き換えます
         <li onclick="presale()">Presale</li>
            <li onclick="claim()">Claim</li>
            <li onclick="stake()">Stake</li>
        
これとともに
            <li onclick="toggle('presale')">Presale</li>
            <li onclick="toggle('claim')">Claim</li>
            <li onclick="toggle('stake')">Stake</li>
        
小次郎又三郎
同じクラス(たとえば my_div)をすべての表示可能ファイルに割り当ててから、を関数divに渡すことができidます(これにより、それが表示され、他のすべてが非表示になります)。
        function show_hide(id) {
          document.querySelectorAll('.my_div').forEach(my_div => {
            my_div.style.display = my_div.getAttribute('id') == id ? 'block' : 'none';
          });
        }
        
        .my_div {
          display: none;
        }
        
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
        <div>
          <ul>
            <li onclick="show_hide('presale')">Presale</li>
            <li onclick="show_hide('claim')">Claim</li>
            <li onclick="show_hide('stake')">Stake</li>
          </ul>
          <div class="my_div" id="presale">
            <h1>Presale</h1>
          </div>
          <div class="my_div" id="claim">
            <h1>Claim</h1>
          </div>
          <div class="my_div" id="stake">
            <h1>Stake</h1>
          </div>
        </div>
        
小次郎又三郎
これが私の試みです。@ztomの答えと同じですが、私は。を避けようとしましたforeach。
        document.querySelectorAll("li").forEach(e => e.addEventListener("click", () => {
          let shown = document.querySelector(".action:not(.d-none)")
          if(shown){
            shown.classList.add("d-none")
            if(e.dataset.id != shown.id){
              document.getElementById(e.dataset.id).classList.remove("d-none")
            }
          }else{
            document.getElementById(e.dataset.id).classList.remove("d-none")
          }
        }))
        
        .action{
          display:grid;
        }
        .d-none{
          display:none;
        }
        
        <ul>
          <li data-id="presale">Presale</li>
          <li data-id="claim">Claim</li>
          <li data-id="stake">Stake</li>
        </ul>
        <div class="action d-none" id="presale">Presale</div>
        <div class="action d-none" id="claim">Claim</div>
        <div class="action d-none" id="stake">Stake</div>
        
小次郎又三郎
リストアイテムと「パネル」の両方にデータ属性を付加する場合は、1つの関数を使用してそれらを照合し、CSSクラスを使用してアクティブにするかどうかを決定できます。
        // Cache the elements, the panels container, and the list element
        // separately adding one event listener to the list. We're using
        // event delegation for this - one listener captures all
        // the events from its child elements
        const allElements = document.querySelectorAll('.list li, .panels .panel');
        const panels = document.querySelector('.panels');
        const list = document.querySelector('ul');
        list.addEventListener('click', handlePanel);
        
        // When the listener is triggered
        function handlePanel(e) {
          
          // Check if it's a list item
          if (e.target.matches('li')) {
        
            // Destructure its id from the dataset
            const { id } = e.target.dataset;
        
            // Remove all the active classes from the elements  
            allElements.forEach(el => el.classList.remove('active'));
        
            // And then add an active class to the list item,
            // and the panel where their ids match
            const selector = `[data-id="${id}"]`;
            const item = list.querySelector(`li${selector}`);
            const panel = panels.querySelector(`.panel${selector}`);
            
            item.classList.add('active');
            panel.classList.add('active');
          
          }
        
        }
        
        .panel { display: none; }
        .panel h1 { font-size: 1.2em; color: darkblue; }
        ul { list-style-type: none; margin-left: 0; padding: 0; }
        li { padding: 0.3em; border: 1px solid white; }
        li:hover { background-color: thistle; cursor: pointer; }
        li.active { border: 1px solid #454545; background-color: lightyellow; }
        .panel.active { display: block; }
        
        <ul class="list">
          <li data-id="presale">Presale</li>
          <li data-id="claim">Claim</li>
          <li data-id="stake">Stake</li>
        </ul>
        
        <div class="panels">
          <div data-id="presale" class="panel">
            <h1>Presale</h1>
          </div>
          <div data-id="claim" class="panel">
            <h1>Claim</h1>
          </div>
          <div data-id="stake" class="panel">
            <h1>Stake</h1>
          </div>
        </div>
        
小次郎又三郎
複数の要素で同じロジックを使用する場合は、idの代わりにクラスを使用すると、ソリューションはデフォルトで短縮されます。 を使用jQueryすると、基本的に2ライナーになります。 CSSでは、 Yourを使用してクラス.hiddenを作成し、クラスも使用して要素をグループ化する必要があります。display:none;divli 次に、このクラスを参照して、次の方法で表示/非表示ロジックを追加できます。
        $('h1:contains('+$(this).text()+')').parent().toggleClass("hidden"); 
        $('h1:not(:contains('+$(this).text()+'))').parent().addClass("hidden");
        
小次郎又三郎