iframe(スクロールバー無し+クロスドメイン)のページ内リンク

あまり…ほとんど需要が無いと思いますが、以前詰まった iframeのページ内リンクについて書きます。

あるwebサービスで別途作成したhtmlコンテンツを表示させるためにiframeを使用しました。 その際にhtmlコンテンツでページ内リンクが効かないという問題が発生しました。

iframeにスクロールバーがあれば通常の方法でページ内リンクができるのですが、 1枚のページであるように見せるため、スクロールバーを表示させることはできません。 また、クロスドメインの場合、親子間でオブジェクトの操作ができないようです(XSRF防止のため)

色々試した結果、javascriptのpostMessage(子 - htmlコンテンツ)とaddEventListener(親 - 元のwebサービス)の組み合わせで実現できました。

子から親にpostMessageでスクロール先のY座標を通知 ↓ 親がaddEventListenerで登録したコールバック先でスクロール処理

kodomo.html(子)

<html>
    <head>
        <script type="text/javascript">
        $(document).ready(function(){
            // 親フレームにスクロール(=ページ内リンク)する命令を送る
            $(".PageNaiLink").click(function(){
                var parentFrame = parent.postMessage ? parent : (parent.document.postMessage ? parent.document : undefined);
                var target = $(this).attr("href");
                if(typeof parentFrame != "undefined"){
                    
                    // 【メインの処理】
                    // messageイベントで処理を識別する文字列(この場合は'page_nai_link')と飛び先のy座標を送る
                    // ※この場合、リンク元のタグのhref属性は'#リンク先'のみ
                    parentFrame.postMessage( "page_nai_link" + $(target).offset().top, "*");
                    
                }else{
                    // エラー処理
                }
            });
        });
        </script>
    </head>
    <body>
        <!-- ページ内リンク -->
        <a class="PageNaiLink" href="#link1">ページ内リンク1へ</a><br />
        <a class="PageNaiLink" href="#linl2">ページ内リンク2へ</a><br />
        <a class="PageNaiLink" href="#link3">ページ内リンク3へ</a><br />
        <a class="PageNaiLink" href="#link4">ページ内リンク4へ</a><br />
        <!-- ページ内リンク end -->

        <div style="height:200px;"></div><!-- 余白 -->

        <a id="link1"></a>リンク1

        <div style="height:200px;"></div><!-- 余白 -->

        <a id="link2"></a>リンク2

        <div style="height:200px;"></div><!-- 余白 -->

        <a id="link3"></a>リンク3

        <div style="height:200px;"></div><!-- 余白 -->

        <a id="link4"></a>リンク4
    </body>
</html>

 

oya.html(親)

<html>
    <head>
        <script type="text/javascript">
        // messageイベントのコールバック関数を登録します。
        window.addEventListener("message", receiveSize, false);

        function receiveSize(e) {
            
            // 【メインの処理】
            // messageイベントは一つしか無いので、複数の処理で使いまわすことになります。
            // そのため、kodomo.htmlから送信する文字列内に処理内容を識別できる文字列(この場合は'page_nai_link')を
            // 付けています
            if( typeof e.data == "string" && 0 == e.data.indexOf("page_nai_link") ){
                var scrollVal = parseInt(e.data.replace('page_nai_link', ''));
                $('html,body').scrollTop(scrollVal);
            }
        }
        </script>
    </head>
    <body>
        <!-- 別途作成したコンテンツを表示(スクロールバー無し・異なるドメイン) -->
        <iframe  src="http://betsu.domain.com/kodomo.html" id="" height="950" style="border:0" />


    
    </body>
</html>