上毛印刷株式会社

【JavaScript】QRコードを読み取って、特定のモーダルウィンドウを表示する

【JavaScript】QRコードを読み取って、特定のモーダルウィンドウを表示する

2024年06月17日
WEBサイト制作
  • #HTML
  • #css
  • #JavaScript
  • #tips

こんにちは!
上毛印刷WEB制作担当のソーヤです。

今回は以前の記事の続きになります。

◆過去記事はコチラ(【JavaScript】クリックしたらモーダルウィンドウで詳細情報を表示する)

ある日、QRコードを読み取って特定のモーダルウィンドウを表示することはできないか?
という要望を受けました。
というわけで実装!
QRコード一覧
お手持ちのスマートフォンで、それぞれのQRコードを読み取ってみてください!
QRコードに対応したモーダルウィンドウが表示されていると思います。

ちなみにPCの方はこちら↓↓↓
ネコ(別ウィンドウで開きます)
イヌ(別ウィンドウで開きます)
鰤(別ウィンドウで開きます)
蕎麦(別ウィンドウで開きます)
ビール(別ウィンドウで開きます)
亀の天国(別ウィンドウで開きます)
スバメの巣(別ウィンドウで開きます)

HTML例

<div class="modal-wrap">
  <div class="modalList-item js-item" id="cat">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/06/IMG_1669.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modalInner-img">
              <img src="/cp/wp/wp-content/uploads/2024/06/IMG_1669.jpg" alt="">
            </div>
            <div class="modalInner-item">
              <p>モーダルウィンドウが開きました。<br>ここにコンテンツを入れてください。<br> ネコかわいいですね。</p>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="modalList-item js-item" id="dog">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/06/dog.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modalInner-img">
              <img src="/cp/wp/wp-content/uploads/2024/06/dog.jpg" alt="">
            </div>
            <div class="modalInner-item">
              <p>モーダルウィンドウが開きました。<br>ここにコンテンツを入れてください。<br> イヌかわいいですね。</p>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="modalList-item js-item" id="yellowtail">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/06/buri.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modalInner-img">
              <img src="/cp/wp/wp-content/uploads/2024/06/buri.jpg" alt="">
            </div>
            <div class="modalInner-item">
              <p>モーダルウィンドウが開きました。<br>ここにコンテンツを入れてください。<br> 鰤うまそうですね。</p>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="modalList-item js-item" id="soba">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/06/soba.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modalInner-img">
              <img src="/cp/wp/wp-content/uploads/2024/06/soba.jpg" alt="">
            </div>
            <div class="modalInner-item">
              <p>モーダルウィンドウが開きました。<br>ここにコンテンツを入れてください。<br> 蕎麦の季節になりました。</p>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="modalList-item js-item" id="beer">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/06/god.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modalInner-img">
              <img src="/cp/wp/wp-content/uploads/2024/06/god.jpg" alt="">
            </div>
            <div class="modalInner-item">
              <p>モーダルウィンドウが開きました。<br>ここにコンテンツを入れてください。<br> アルコール度数高めです。</p>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="modalList-item js-item" id="turtle">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/06/kame.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modalInner-img">
              <img src="/cp/wp/wp-content/uploads/2024/06/kame.jpg" alt="">
            </div>
            <div class="modalInner-item">
              <p>モーダルウィンドウが開きました。<br>ここにコンテンツを入れてください。<br> 亀の楽園。</p>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="modalList-item js-item" id="swallow">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/06/tsubame.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modalInner-img">
              <img src="/cp/wp/wp-content/uploads/2024/06/tsubame.jpg" alt="">
            </div>
            <div class="modalInner-item">
              <p>モーダルウィンドウが開きました。<br>ここにコンテンツを入れてください。<br>ツバメを大事にしましょう。</p>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

CSS例

.modal-wrap{
  display: flex;
  flex-wrap: wrap;
}
.modalList-item {
  width: 300px;
  margin: 0 0 30px 0;
  padding: 0 8px;
}
.modalList-item .modal-contents {
  max-width: 700px;
}
.modalList-item a {
  display: block;
  position: relative;
  width: 100%;
  height: 100%;
  color: #333;
  background-color: #fff;
  box-shadow: 9px 8px 10px rgba(0, 0, 0, 0.2), 0 0 5px 0 #ffffff, -4px 0 5px 0 #ffffff, -4px -6px 15px #ffffff;
  transition: .4s ease;
}
.modalList-item a:hover {
  transform: scale(1.01);
  box-shadow: 15px 14px 17px rgba(0, 0, 0, 0.2), 0 0 8px 0 #ffffff, -7px 0 8px 0 #ffffff, -7px -10px 26px #ffffff;
  opacity: 0.7;
}
.modalList-item a:hover::after {
  transform: translateX(10px);
}
.modalList-item h3 {
  padding: 20px 10px 40px;
  font-size: 22px;
  font-weight: bold;
  line-height: 1.2;
}
.modalList-item h3 span {
  font-size: 14px;
}
.modalButton-img {
  position: relative;
}
.modalButton-img img {
  width: 100%;
  max-width: 100%;
  margin: 0 0 20px;
  vertical-align: top;
}
.modalInner-img {
  position: relative;
  margin: 0 0 20px;
}
.modalInner-img img {
  width: 100%;
  max-width: 100%;
  margin: 0 0 20px;
  vertical-align: top;
}
.modalInner-img + h3 {
  display: flex;
  -webkit-box-align: end;
  -webkit-align-items: flex-end;
  -ms-flex-align: end;
  align-items: flex-end;
  padding: 0 10px 20px 0;
}
.modalList-item .modal-contents {
    max-width: 700px;
}
.modal {
  display: none;
  z-index: 9999;
  position: fixed;
  top: -10px;
  right: 0;
  bottom: -10px;
  left: 0;
  overflow: hidden;
  overflow-y: auto;
  backface-visibility: hidden;
  background-color: rgba(0, 0, 0, 0.45);
}
.modal-container {
  display: table;
  width: 100%;
  height: 100%;
  padding: 10px 0;
}
.modal-inner {
  display: table-cell;
  padding: 2.7em 2em;
  vertical-align: middle;
}
.modal-contents {
  position: relative;
  max-width: 1300px;
  margin: 0 auto;
  padding: 10px;
  background-color: #fff;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
  text-justify: inter-ideograph;
}
.modal-button-wrap {
  position: absolute;
  top: 20px;
  right: 20px;
}
.modal-button {
  appearance: none;
  display: inline-block;
  position: relative;
  width: 24px;
  height: 24px;
  border: none;
  outline: none;
  background: transparent;
  line-height: 1;
  text-indent: -9999px;
  vertical-align: middle;
  cursor: pointer;
}
.modal-button::before {
  position: absolute;
  top: -71px;
  left: 7px;
  width: 30px;
  height: 30px;
  border: 5px solid #fff;
  border-radius: 50%;
  background-color: #fff;
  background-image: url(/cp/wp/wp-content/uploads/2024/06/modal_close.png);
  background-position: center center;
  background-repeat: no-repeat;
  background-size: contain;
  content: '';
  cursor: pointer;
}

JavaScript例

document.addEventListener('DOMContentLoaded', function() {
  var windowEl = window,
      html = document.documentElement,
      body = document.body,
      scrollbarWidth = window.innerWidth - document.body.scrollWidth,
      touchStartY;

  windowEl.addEventListener('touchstart', function(event) {
    touchStartY = event.changedTouches[0].screenY;
  });

  document.querySelectorAll('.js-modal').forEach(function(modalTrigger) {
    modalTrigger.addEventListener('click', function() {
      var overlay = modalTrigger.nextElementSibling;
      windowEl.addEventListener('touchmove', touchMoveHandler, { passive: false });
      html.style.overflow = 'hidden';
      body.style.overflow = 'hidden';
      if (scrollbarWidth) {
        html.style.paddingRight = scrollbarWidth + 'px';
      }
      overlay.style.display = 'block';
      overlay.style.opacity = 1;
      overlay.style.transition = 'opacity 0.3s';

      var touchMoveHandler = function(event) {
        var currentY = event.changedTouches[0].screenY,
            height = overlay.offsetHeight,
            isTop = touchStartY <= currentY && overlay.scrollTop === 0, isBottom = touchStartY >= currentY && overlay.scrollHeight - overlay.scrollTop === height;
        if (isTop || isBottom) {
          event.preventDefault();
        }
      };

      var closeModal = function() {
        body.style.removeProperty('overflow');
        html.style.removeProperty('overflow');
        html.style.removeProperty('padding-right');
        windowEl.removeEventListener('touchmove', touchMoveHandler);
        overlay.style.transition = 'opacity 0.3s';
        overlay.style.opacity = 0;
        setTimeout(function() {
          overlay.scrollTop = 0;
          overlay.style.display = 'none';
          overlay.style.removeProperty('style');
          html.style.removeProperty('style');
        }, 300);
      };

      overlay.addEventListener('click', function(event) {
        if (!event.target.closest('.modal-contents')) {
          closeModal();
        }
      });

      overlay.querySelector('.modal-button').addEventListener('click', function() {
        closeModal();
      });
    });
  });
});
document.querySelectorAll('.modal').forEach(function(modalMatter) {
  modalMatter.addEventListener('click', function() {
    if (!event.target.closest('.modal-contents')) {
    setTimeout(function() {
      modalMatter.scrollTop = 0;
      modalMatter.style.display = 'none';
      modalMatter.style.removeProperty('style');
    }, 300);
    }
  });
  modalMatter.querySelector('.modal-button').addEventListener('click', function() {
    setTimeout(function() {
      modalMatter.scrollTop = 0;
      modalMatter.style.display = 'none';
      modalMatter.style.removeProperty('style');
    }, 300);
  });
});
function onPageLoad() {
  var urlHash = location.hash;
if (window.name !== "any") {
    location.reload();
    window.name = "any";
} else {
    window.name = "";
}
  switch (urlHash) {
      case '#cat':
          document.getElementById('cat').firstElementChild.nextElementSibling.style.display = "block";
          break;
      case '#dog':
          document.getElementById('dog').firstElementChild.nextElementSibling.style.display = "block";
          break;
      case '#yellowtail':
          document.getElementById('yellowtail').firstElementChild.nextElementSibling.style.display = "block";
          break;
      case '#soba':
          document.getElementById('soba').firstElementChild.nextElementSibling.style.display = "block";
          break;
      case '#beer':
          document.getElementById('beer').firstElementChild.nextElementSibling.style.display = "block";
          break;
      case '#turtle':
          document.getElementById('turtle').firstElementChild.nextElementSibling.style.display = "block";
          break;
      case '#swallow':
          document.getElementById('swallow').firstElementChild.nextElementSibling.style.display = "block";
          break;
      default:
          break;
  }
}
window.addEventListener('load', onPageLoad);
window.addEventListener('pageshow', function(event) {
    if (event.persisted) {
        onPageLoad();        
    }
});
history.replaceState(null, document.getElementsByTagName('title')[0].innerHTML, null);
window.addEventListener('popstate', function(e) {
  onPageLoad();
});

Androidだと問題なく動くんですが、iPhoneだとうまくいかず結構手こずりました・・・

まとめ

今回もjQueryではなく、Vanilla.jsで実装してみました。

コピペしてガンガン使ってください!

WEB制作担当ソーヤ

ソーヤ

上毛印刷WEB制作担当
前職は東証プライム企業の本社WEB受託チームにてフロントエンドエンジニアを3年経験。


この記事に対するご意見・ご感想・ご質問等ありましたら、
ぜひ下記フォームにてお送りください。

    お名前必須
    メールアドレス必須
    お問い合わせ内容必須
    PAGE TOP