iframe を iframe ぽく見せない jQuery プラグインを作ってみた
更新履歴
社内アプリも Ajax 的な UI なものが増えるにつれて、1画面にたくさんの機能を詰め込みたいという要望を受ける事が多くなりました。素直に作るとプログラムも肥大化し保守も大変になるので、機能単位に画面を分けて作成し、それぞれの画面を iframe で1つの画面に読み込むといった方法で対応したりしてます(iGoogle 的な感じ)。
その際 「iframe 使ってます感」がでないようにするため、枠線/スクロールバーの消去やコンテンツサイズに合わせた iframe サイズの調整を行うのですが、毎回この処理を書くのも面倒なので jQuery プラグイン化して簡単に使えるようにしてみました。
機能概要
下記画面のように TODO 管理アプリを iframe で読み込んでみます。スクロールバーが表示されコンテンツも隠れて見栄えがよろしくありません。
プラグインを適用するとコンテンツ全体が表示されるように iframe のサイズ調整がされ「iframe 使ってます感」がなくなります。
iframe 内アプリのリロードや DOM 構成の変更等でコンテンツサイズが変更された場合でも、自動的にサイズ調整が行われます。
使用上の注意
- 親ページと iframe 内ページは同一ドメイン上に配置してください。
- IE8 の場合のみ JavaScript 経由で動的に iframe の外枠(border)を消す事ができないようです。クロスブラウザで対応させる必要がある場合は、以下のように iframe 自身に frameborder="0" を記述ください。
<iframe frameborder="0" src="hoge.html"></iframe>
使い方
jQuery と jQuery.exFitFrame.js を読み込みます。
<script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="jquery.exfitframe.js"></script>
適用したい iframe に対し、exFitFrame() メソッドを実行します。
$('iframe.sample').exFitFrame();
TODO アプリの入力フィールドに適当な文字を入力し、登録ボタンを押すとリスト項目に入力内容が追加されます。削除マーク(×)のクリックでリスト項目が削除されます。その際、リスト項目の増減に応じコンテンツサイズが伸縮しますが、iframe のサイズもこれに同期し常にコンテンツ全体が見えるように自動調整されます。
水平方向のサイズ調整
コンテンツが水平方向に広がった場合どうなるか見てみます。iframe のサイズが分かるように css パラメータで外枠を付け、横幅が広がるように半角文字列の羅列を空白をはさまず入力してみます。
$('iframe.sample').exFitFrame({ css : { border:'solid 1px #ddd' } });
文字列の後ろの方が隠れてしまいます。このような場合、 widthFit パラメータを false にし、水平方向の拡張を抑止することでスクロールバーを表示させ、隠れた部分の参照を可能にすることもできます。
$('iframe.sample').exFitFrame({ widthFit : false });
サイズ伸縮の監視処理
コンテンツのサイズ伸縮の検出は、setTimeout の監視により行ってますが、リソースをとられたくない、コンテンツの伸縮が発生しない等の理由で setTimeout を発生させたくない場合は、watchFit パラメータを false にします。
$('iframe.sample').exFitFrame({ watchFit : false });
API によるサイズ調整
api パラメータを指定すると api オブジェクトを取得することができます。api オブジェクトの fit() メソッドを使用することで任意のタイミングによるサイズ調整が可能です。setTimeout を発生させず自前でサイズ調整を行う場合は以下のように記述します。
//サイズ調整処理 var fit = function( api ){ //iframe 内の document 取得 var doc = api.getContents(); if( doc ){ //登録 or 削除時にサイズ調整 doc.find('body').click(function(evt){ if(evt.target.id == 'add' || $(evt.target).hasClass('del')){ api.fit(); } }); } } //api オブジェクトの取得 var api = $('iframe.sample').exFitFrame({ api : true, watchFit : false, load : function( api ){ //iframe 内ロード時にサイズ調整 fit( api ); } }); //サイズ調整 fit( api );
プラグインを適用してる iframe が複数ある場合は、each() や eq() メソッドでそれぞれの API にアクセスすることができます。(詳しくはこちら「jQuery ライクなプラグイン API の定義方法を考えてみる - Cyokodog::Diary」をご参照ください)
var api = $('#iframe1,#iframe2').exFitFrame({ api : true }); api.each(function(){ $(this).fit(); //1周目:iframe1 の API、2周目:iframe2 の API }); api.eq(1).fit(); //iframe2 の API
パラメータ
下記パラメータがあります。
- api
- 初期値:false
true にすると api オブジェクトを返します。 - widthFit
- 初期値:true
水平方向のサイズ調整を行います。 - heightFit
- 初期値:true
垂直方向のサイズ調整を行います。 - loadFit
- 初期値:true
iframe 内コンテンツがリロードされた場合サイズ調整を行います。 - watchFit
- 初期値:500
指定時間単位で setTimeout でコンテンツサイズの変化を監視し、変化があったのみサイズ調整を行います。監視を行わない場合は false を指定します。 - load
- 初期値:null
iframe の load イベントの callback 関数を指定できます。callback 関数の第1引数には API オブジェクトが引き渡されます。 - css
- 初期値:null
jQuery の css() メソッドと同様に json 形式で iframe に対する css を指定できます。
API
下記 メソッドがあります。
- fit()
- パラメータの widthFit / heightFit に従いサイズ調整をします。
- widthFit()
- 水平方向のサイズ調整をします。
- heightFit()
- 垂直方向のサイズ調整をします。
- watchFit( time )
- 引数で指定された時間間隔で iframe コンテンツのサイズ変化を監視し、変化のあった場合、パラメータの widthFit / heightFit に従いサイズ調整をします。
- getContents()
- iframe 内の document オブジェクトを jQuery 形式で返します。
- getTargets()
- 処理対象となった iframe を jQuery 形式で返します。
- getTarget()
- 処理対象となった iframe を jQuery 形式で返します。複数の iframe に対し処理を適用してた場合は先頭の iframe のみを返します。
iframe の使いどころ
iGoogle のような使い方もありますが、jQuery を使うと iframe 間のデータや処理の受け渡しもさほど難しくないので(下記参照)、親ページや他の iframe との対話が必要となる汎用的な画面処理を REST ベースでサービス化して各システムで再利用するというのもいいかもしれません。(ワークフロー系システムで必要になる社員選択機能やファイルアップロード機能などで使ってます。)
対話が必要なサービスという意味合いでは同一ドメインの問題がネックになりますが、ちょっと試したところ iframe 内 iframe(下記参照)を使うとある程度解決できるようなので、機会があったらその辺についてももう少し調べて記事にしてみたいと思います。