綺麗に死ぬITエンジニア

Javascript(jQuery)でiframe内のイベントを親フレームで取得する

2016-11-15

iframeを利用する上で、最も障害となるものの一つに、ページ間のJavascriptの連携のしにくさが挙げられます。

通常のWebページでは、windowオブジェクトは1つですから、何も考えることなく普通にwindowオブジェクトを使えば良いです。しかし、iframeを利用したWebページでは、iframeタグを記述した呼び出し元Webページ(親フレーム)と、iframeによって呼び出された呼び出し先Webページ(子フレーム)の、2つのwindowオブジェクトが生成されます。よって、それぞれを組み合わせて簡単に呼んだり変更したりといった記述が通常に比べ難しく、更に記述が煩雑になりがちです。

当然、iframeを使うと、親ページ内で一貫して利用しているイベントが、iframeのページ内でのみ、動作しなくなります。例えば、以下のような場合、子フレーム内でどれだけマウスを動かしても、親フレームではそのイベントを取得できません。

<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"
            integrity="sha256-/SIrNqv8h6QGKDuNoLGA4iret+kyesCkHGzVUUV0shc="
            crossorigin="anonymous"></script>
    <script>
      jQuery(function ($) {
        $(window).on('mousemove', onMouseMove);

        function onMouseMove() {
          console.log('マウス動いた!');
        }
      });
    </script>
  </head>
  <body>
    <main>
      <p>親フレームです。</p>
      <iframe src="child.html"></iframe>
    </main>
  </body>
</html>
<html>
  <head></head>
  <body>
    <main>
      <p>子フレームです。</p>
    </main>
  </body>
</html>

デモ(動作しない)

子フレーム上でどれだけマウスを動かしても、コンソールに「マウス動いた!」と表示されることはないです。

これを解消し、子フレーム内でのイベントを親フレーム内で取得するには、以下のようにします(jQuery使用)。

<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"
            integrity="sha256-/SIrNqv8h6QGKDuNoLGA4iret+kyesCkHGzVUUV0shc="
            crossorigin="anonymous"></script>
    <script>
      jQuery(function ($) {
        // 親フレームのイベント
        $(window).on('mousemove', onMouseMove);

        // 子フレームのイベント
        $('iframe').on('load', function () {
          $(this).contents().on('mousemove', onMouseMove);
        });

        function onMouseMove() {
          console.log('マウス動いた!');
        }
      });
    </script>
  </head>
  <body>
    <main>
      <p>親フレームです。</p>
      <iframe src="child.html"></iframe>
    </main>
  </body>
</html>
<html>
  <head></head>
  <body>
    <main>
      <p>子フレームです。</p>
    </main>
  </body>
</html>

デモ(jQuery有り)

jQueryを使わずに実装する場合は、以下のようにすればいいでしょう。

<html>
  <head>
    <script>
      document.addEventListener('DOMContentLoaded', function () {
        // 親フレームのイベント
        document.addEventListener('mousemove', onMouseMove);

        // 子フレームのイベント
        var iframeElements = document.getElementsByTagName('iframe');
        for (var i = 0; i < iframeElements.length; i++) {
          iframeElements[i].addEventListener('load', (function (element) {
            return function () {
              element.contentWindow.document.addEventListener('mousemove', onMouseMove);
            };
          })(iframeElements[i]), false);
        }

        function onMouseMove() {
          console.log('マウス動いた!');
        }
      }, false);
    </script>
  </head>
  <body>
    <main>
      <p>親フレームです。</p>
      <iframe src="child.html"></iframe>
    </main>
  </body>
</html>
<html>
  <head></head>
  <body>
    <main>
      <p>子フレームです。</p>
    </main>
  </body>
</html>

デモ(jQuery無し)

iframe、便利なんだか不便なんだかわかりませんね。

筆者について

フリーランスエンジニアとして活動している、「もりやませーた」です。

筆者のTwitterはこちら。記事に関するご意見等はTwitterの方へお寄せください。

その他業務に関するお問い合わせは、こちらのページをご覧ください。

JavaScript