Creating Multiple Modals on a Single Page

前端 未结 4 836
南笙
南笙 2020-12-15 14:35

I\'m having some issues creating multiple modals on a single webpage following the sample code from w3schools.com. The code in question that I am using is this one: http://w

相关标签:
4条回答
  • 2020-12-15 15:13

    Update September 2020: The code in my answer is a slightly outdated version of the one in my blog post. Please view the post itself for the most recent version, along with explanations.

    I know I'm necroing a dead post here, but I'd like to propose a cleaner, more maintainable solution. I wrote an in-depth guide on how to create multiple modals on a single page on my blog. The explanations are a bit involved, so if you want to understand how this code works, I break things down in detail in that post.

    Two versions of the code are below, depending on what you want to accomplish: multiple stacked modals or multiple side-by-side modals.

    I hope this helps anyone who comes across this in the future.

    Creating stacked modals

    // Stack of modals
    let currentlyOpenModals = [];
    
    const noModalsOpen = () => !currentlyOpenModals.length;
    
    const openModal = modalId => {
      const modalWrapper = document.getElementById(modalId);
      modalWrapper.classList.add("visible");
      currentlyOpenModals.push(modalWrapper);
    };
    
    // By definition, it's always the topmost modal that will be closed first
    const closeTopmostModal = () => {
      if (noModalsOpen()) {
        return;
      }
    
      const modalWrapper = currentlyOpenModals[currentlyOpenModals.length - 1];
      modalWrapper.classList.remove("visible");
      currentlyOpenModals.pop();
    };
    
    const modalTriggers = document.querySelectorAll(".modal-trigger");
    modalTriggers.forEach(modalTrigger => {
      modalTrigger.addEventListener("click", clickEvent => {
        const trigger = clickEvent.target;
        const modalId = trigger.getAttribute("data-modal-id");
        openModal(modalId);
      });
    });
    
    // Otherwise, clicking the content of a modal will propagate the click to the modal wrapper,
    // and that will close the entire thing. That's not what we want!
    document.querySelectorAll(".modal-window").forEach(modal => {
      modal.addEventListener("click", clickEvent => {
        clickEvent.stopPropagation();
      });
    });
    
    const modalWrappers = document.querySelectorAll(".modal-wrapper");
    modalWrappers.forEach(modalWrapper => {
      modalWrapper.addEventListener("click", () => {
        closeTopmostModal();
      });
    });
    
    document.querySelectorAll(".close-modal-button").forEach(closeModalButton => {
      closeModalButton.addEventListener("click", () => {
        closeTopmostModal();
      });
    });
    
    document.body.addEventListener("keyup", keyEvent => {
      if (keyEvent.key === "Escape") {
        closeTopmostModal();
      }
    });
    * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
    }
    
    body {
        align-items: center;
        display: flex;
        flex-direction: column;
        font-family: Arial;
        font-size: 18px;
        height: 100vh;
        justify-content: center;
    }
    
    p {
        margin-bottom: 1em;
    }
    
    .modal-wrapper {
        align-items: center;
        background-color: rgba(100, 100, 100, 0.5);
        bottom: 0;
        display: flex;
        flex-wrap: wrap;
        height: 100vh;
        justify-content: center;
        left: 0;
        opacity: 0;
        position: fixed;
        right: 0;
        transition: all 0.2s ease-in-out;
        visibility: hidden;
        width: 100%;
        z-index: 1000;
    }
    
    .modal-wrapper.visible {
        opacity: 1;
        visibility: visible;
    }
    
    .modal-window {
        background-color: white;
        border-radius: 5px;
        box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
        padding: 20px;
        transform: scale(0);
        transition: 0.2s ease-in-out all;
    }
    
    .modal-wrapper.visible .modal-window {
        transform: scale(1);
    }
    
    .modal-header {
        align-items: center;
        border-bottom: 2px solid black;
        display: flex;
        justify-content: space-between;
        margin-bottom: 20px;
        padding-bottom: 20px;
    }
    
    .close-modal-button {
        align-items: center;
        cursor: pointer;
        display: flex;
        height: 30px;
        justify-content: center;
        width: 30px;
    }
    
    .close-modal-button::before {
        content: "X";
        color: rgb(112, 112, 112);
    }
    
    .close-modal-button:hover::before {
        color: black;
    }
    
    .modal-trigger, a {
        color: rgb(10, 47, 255);
        cursor: pointer;
        text-decoration: underline;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" type="text/css" href="style.css" />
        <title>Stacked Modals Demo</title>
    </head>
    <body>
        <p>Lorem ipsum. <span class="modal-trigger" data-modal-id="modal1">Click this trigger</span> to open a modal.</p>
        <p>Close a modal by clicking off to the side, clicking the X, or pressing Escape.</p>
        <div class="modal-wrapper" id="modal1">
            <section class="modal-window">
                <header class="modal-header">
                    <h3>Title goes here...</h3>
                    <div class="close-modal-button"></div>
                </header>
                <p>Congrats, you've opened a modal!</p>
                <p>Now open <span class="modal-trigger" data-modal-id="modal2">another modal</span>!</p>
            </section>
        </div>
        <div class="modal-wrapper" id="modal2">
            <section class="modal-window">
                <header class="modal-header">
                    <h3>Modalception                                                                     
    0 讨论(0)
  • 2020-12-15 15:18
    • You assigned the same Id to both modal triggering buttons. Different elements shouldn't have the same Id.

    • In you JavaScript code, you always pick a single element (a single close button, a single open button, etc).

    It's a HTML/JS beginner's mistake I would say. This would work:

    // Get the button that opens the modal
    var btn = document.querySelectorAll("button.modal-button");
    
    // All page modals
    var modals = document.querySelectorAll('.modal');
    
    // Get the <span> element that closes the modal
    var spans = document.getElementsByClassName("close");
    
    // When the user clicks the button, open the modal
    for (var i = 0; i < btn.length; i++) {
     btn[i].onclick = function(e) {
        e.preventDefault();
        modal = document.querySelector(e.target.getAttribute("href"));
        modal.style.display = "block";
     }
    }
    
    // When the user clicks on <span> (x), close the modal
    for (var i = 0; i < spans.length; i++) {
     spans[i].onclick = function() {
        for (var index in modals) {
          if (typeof modals[index].style !== 'undefined') modals[index].style.display = "none";    
        }
     }
    }
    
    // When the user clicks anywhere outside of the modal, close it
    window.onclick = function(event) {
        if (event.target.classList.contains('modal')) {
         for (var index in modals) {
          if (typeof modals[index].style !== 'undefined') modals[index].style.display = "none";    
         }
        }
    }
    /* The Modal (background) */
    .modal {
        display: none; /* Hidden by default */
        position: fixed; /* Stay in place */
        z-index: 1; /* Sit on top */
        padding-top: 100px; /* Location of the box */
        left: 0;
        top: 0;
        width: 100%; /* Full width */
        height: 100%; /* Full height */
        overflow: auto; /* Enable scroll if needed */
        background-color: rgb(0,0,0); /* Fallback color */
        background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
    }
    
    /* Modal Content */
    .modal-content {
        position: relative;
        background-color: #fefefe;
        margin: auto;
        padding: 0;
        border: 1px solid #888;
        width: 80%;
        box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
        -webkit-animation-name: animatetop;
        -webkit-animation-duration: 0.4s;
        animation-name: animatetop;
        animation-duration: 0.4s
    }
    
    /* Add Animation */
    @-webkit-keyframes animatetop {
        from {top:-300px; opacity:0}
        to {top:0; opacity:1}
    }
    
    @keyframes animatetop {
        from {top:-300px; opacity:0}
        to {top:0; opacity:1}
    }
    
    /* The Close Button */
    .close {
        color: white;
        float: right;
        font-size: 28px;
        font-weight: bold;
    }
    
    .close:hover,
    .close:focus {
        color: #000;
        text-decoration: none;
        cursor: pointer;
    }
    
    .modal-header {
        padding: 2px 16px;
        background-color: #5cb85c;
        color: white;
    }
    
    .modal-body {padding: 2px 16px;}
    
    .modal-footer {
        padding: 2px 16px;
        background-color: #5cb85c;
        color: white;
    }
    <h2>1st Modal</h2>
    
    <!-- Trigger/Open The Modal -->
    <button class="modal-button" href="#myModal1">Open Modal</button>
    
    <!-- The Modal -->
    <div id="myModal1" class="modal">
    
      <!-- Modal content -->
      <div class="modal-content">
        <div class="modal-header">
          <span class="close">×</span>
          <h2>Modal Header</h2>
        </div>
        <div class="modal-body">
          <p>Some text in the Modal Body</p>
          <p>Some other text...</p>
        </div>
        <div class="modal-footer">
          <h3>Modal Footer</h3>
        </div>
      </div>
    
    </div>
    
    <h2>2nd Modal</h2>
    
    <!-- Trigger/Open The Modal -->
    <button class="modal-button" href="#myModal2">Open Modal</button>
    
    <!-- The Modal -->
    <div id="myModal2" class="modal">
    
      <!-- Modal content -->
      <div class="modal-content">
        <div class="modal-header">
          <span class="close">×</span>
          <h2>Modal Header</h2>
        </div>
        <div class="modal-body">
          <p>Some text in the Modal Body</p>
          <p>Some other text...</p>
        </div>
        <div class="modal-footer">
          <h3>Modal Footer</h3>
        </div>
      </div>
    
    </div>

    0 讨论(0)
  • 2020-12-15 15:31

    On your JSFiddle, make sure you use class="myBtn" instead of id="myBtn" then it should work.

    Here is the full working code:

    HTML:

    <h2>1st Modal</h2>
    
    <!-- Trigger/Open The Modal -->
    <button class="myBtn">Open Modal</button>
    
    <!-- The Modal -->
    <div id="myModal" class="modal">
    
      <!-- Modal content -->
      <div class="modal-content">
        <div class="modal-header">
          <span class="close">×</span>
          <h2>Modal Header</h2>
        </div>
        <div class="modal-body">
          <p>Some text in the Modal Body</p>
          <p>Some other text...</p>
        </div>
        <div class="modal-footer">
          <h3>Modal Footer</h3>
        </div>
      </div>
    
    </div>
    
    <h2>2nd Modal</h2>
    
    <!-- Trigger/Open The Modal -->
    <button class="myBtn">Open Modal</button>
    
    <!-- The Modal -->
    <div id="myModal2" class="modal">
    
      <!-- Modal content -->
      <div class="modal2-content">
        <div class="modal-header">
          <span class="close">×</span>
          <h2>Modal Header</h2>
        </div>
        <div class="modal-body">
          <p>Some text in the Modal Body</p>
          <p>Some other text...</p>
        </div>
        <div class="modal-footer">
          <h3>Modal Footer</h3>
        </div>
      </div>
    
    </div>
    

    JS:

    // Get the modal
    var modal = document.getElementsByClassName('modal');
    
    // Get the button that opens the modal
    var btn = document.getElementsByClassName("myBtn");
    
    
    // Get the <span> element that closes the modal
    var span = document.getElementsByClassName("close");
    
    // When the user clicks the button, open the modal 
    btn[0].onclick = function() {
        modal[0].style.display = "block";
    }
    
    btn[1].onclick = function() {
        modal[1].style.display = "block";
    }
    // When the user clicks on <span> (x), close the modal
    span[0].onclick = function() {
        modal[0].style.display = "none";
    }
    
    span[1].onclick = function() {
        modal[1].style.display = "none";
    }
    // When the user clicks anywhere outside of the modal, close it
    window.onclick = function(event) {
        if (event.target == modal) {
            modal.style.display = "none";
        }
    }
    
    0 讨论(0)
  • 2020-12-15 15:31

    Why are you using so much code, and javascript to do something you can do using just CSS and HTML? (simplified example, animations and such can of course be added)

    [id^=modal] {
      display: none;
      border: 1px solid red;
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%,-50%);
      min-height: 3em;
      min-width: 5em;
      max-width: 10em;
      }
    input[type=checkbox] {
      position: absolute;
      clip: rect(0 0 0 0);
      }
    #modal1:target {
      display: block;
      }
    #modal2:target {
      display: block;
      }
    [id^=modal] a {
      float: right;
      }
    <div id="content">
        <p>This is the content-container</p>
        <a href="#modal1">Open first modal</a><br>
        <a href="#modal2">Open second modal</a>
      <div id="modal1"><a href="#">Close</a>This is the first modal</div>
      <div id="modal2"><a href="#">Close</a>This is the second modal</div>
    </div>

    0 讨论(0)
提交回复
热议问题