デモページ
※ 下の灰色の部分は全て IFRAME で、ブラウザのサイズ変更と同期します
結論から言いますと、IFRAME と FRAME の大きな違いは、上の画像のように jQuery の DatePicker のカレンダーが、IFRAME の上に展開されるというところです。FRAME の場合ですと、ブラウザが用意するコンボボックス等は FRAME の境界を越えて表示されますが、HTML で作成されるコンテンツは FRAME の境界の下に潜り込んでしまいます。
しかし、FRAME の便利な点は、WEB ページのデータ送信の結果を一方通行で別の FRAME に表示できるので、WEB アプリが元のページの内容を書き換える必要が無いところです。当然その特性は IFRAME も持っていますが、IFRAME は固定のウインドウとして表示されるものなので、ブラウザの大きさに同期して表示部分いっぱいいっぱいで利用するには( FRAME のように )、JavaScript でリアルタイムでサイズを変更する必要があります。
にもかかわらず、実際実装しようとすると、ページの縦のサイズを取得しようとすると、IFRAME が表示されているとうまく取得できない仕様になっていて、たいていは失敗する事になります。これを避けるには、IFRAME のサイズ変更は、IFRAME を非表示にして行う事で解決できました。
古い IE のシステムを想定して、IE8 で動作させる為に、header 関数で『x-ua-compatible: IE=8』 を送っています。
IE8 前提なので、jQuery のバージョンは低く設定しています
IE8 では、IFRAME の境界を CSS で消せませんので frameborder を使用しています
IE、Firefox、Google Chronme で正しく動作する為に、縦の補正値を使用しています
shift_jis を使用しているのは、SQLServer を ODBC 関数でアクセスする予定だからです
FORM の送り先は、accept-charset="utf-8" を使用して utf-8 を利用しています( 但しこの機能は IE8 コンパチブルでは動作しないので、受け取り側で対処する必要があります )
デモページのコード
<?php header( "Content-Type: text/html; Charset=shift_jis" ); header( "Expires: Wed, 31 May 2000 14:59:58 GMT" ); header( "x-ua-compatible: IE=8" ); ?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=shift_jis"> <!-- jQuery のバージョンが 1.9 なのは、IE 用 --> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/jquery-ui.css"> <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/jquery-ui.min.js"></script> <style> body { margin: 0; } #wrapper { background-color: #ffffff; } #head_unit { height: 50px; padding: 15px 0 10px 15px; } #target { /* IFRAME の横調整は、ブラウザに任せます */ width: 100%; } </style> <script> // IFRAME フィット function control_page_iframe(iframe_id) { var height = Math.max(document.documentElement.scrollHeight,document.body.scrollHeight); var head_height = document.getElementById("head_unit").clientHeight; // -6 は、IE と Firefox 用。Google Chrome は 0 で正しくフィットするが、 // IE と Firefox では、BODY のスクロールバーが表示されてしまう( バグレベルの動作 ) document.getElementById(iframe_id).style.height = (height - parseInt(head_height)-6) + "px" } // 日付フォーマット用の文字列処理3つ String.prototype.right = function(n){ var str = this.valueOf(); str = str.substr(str.length-n,n); return str; } String.prototype.zero = function(n){ var strzero = "0000000000000000000"; var str = this.valueOf(); str = strzero + str; return str.right(n); } Date.prototype.datestr = function(sep){ str = this.getFullYear() + sep + (this.getMonth()+1).toString().zero(2) + sep + (this.getDate()).toString().zero(2); return str; } // jQuery DatePicker 用設定データ var datepicker_option = { dateFormat: 'yy/mm/dd', dayNamesMin: ['日', '月', '火', '水', '木', '金', '土'], monthNames: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], showMonthAfterYear: true, yearSuffix: '年', changeYear: true, showAnim: 'fadeIn' } var datepicker; // jQuery 初期処理 $(function() { // jQuery DatePicker プラグイン // ※ 通常フィールド datepicker = $("#datepicker") .datepicker(datepicker_option) .val( (new Date()).datestr("/") ) .css( "width", "100px" ); // この処理は、IE のみで動作します $("#target").on("focus",function(){ datepicker.datepicker( "hide" ); }); // jQuery DatePicker プラグイン // ※ ダイアログ表示 $("#datetDialog").click( function() { $( "#datepicker" ).datepicker( "dialog", $("#datepicker").val(), function(sdate) { $("#datepicker").val( sdate ); }, datepicker_option ); } ); // Google Chrome 用 $("#targetDate").val((new Date()).datestr("-")); // IFRAME フィット用 $(window).on("resize", function(){ var iframe_id = "target"; document.getElementById(iframe_id).style.display = "none"; control_page_iframe(iframe_id); document.getElementById(iframe_id).style.display = ""; }); // 初期 IFRAME フィット control_page_iframe("target"); }); </script> </head> <body> <div id="wrapper"> <div id="head_unit"> <form target="target_iframe" action="iframe_test.php" accept-charset="utf-8"> <input id="targetDate" name="date" type="date"> <input type="submit" name="send" value="送信"> <input type="submit" name="send" value="リセット"> jQuery DatePicker: <input name="date2" type="text" id="datepicker"> <input id="datetDialog" type="button" value="dialog"> </form> </div> <!-- frameborder はサイズ調整させるので境界は無しで設定 --> <!-- ここでは IE8 コンパチブルなので CSS では消せません --> <iframe id="target" name="target_iframe" frameborder="0" src="iframe_test2.php" ></iframe> </div> </body> </html>
▼ IFRAME 内のコード
<?php header( "Content-Type: text/html; Charset=shift_jis" ); header( "Expires: Wed, 31 May 2000 14:59:58 GMT" ); // IE 用 header( "x-ua-compatible: IE=8" ); ?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=shift_jis"> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/jquery-ui.css"> <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/jquery-ui.min.js"></script> <script> $(function() { // この処理は、一般的なブラウザと最新の IE( IE11で確認 )で動作します $(window).on("focus",function(){ parent.datepicker.datepicker( "hide" ); }); }); </script> <style> body { background-color: #c0c0c0; } </style> </head> <body> <img src="https://lh6.googleusercontent.com/-ShzpKMxTsDU/VJ6mrePilbI/AAAAAAAAYA8/YNag5FGr5Qg/s402/freefont_logo_kana003.png" style="border: solid 0px #000000"> <br><br> あいうえおかきくけこさしすせそたちつてとあいうえおかきくけこさしすせそたちつてとあいうえおかきくけこさしすせそたちつてとあいうえおかきくけこさしすせそたちつてとあいうえおかきくけこさしすせそたちつてとあいうえおかきくけこさしすせそたちつてとあいうえおかきくけこさしすせそたちつてと </body> </html>
このページのコードは、INPUT 要素の type="date" の利用のテストも兼ねています。jQuery を使ってしまったほうが簡単ではありますが、既存の FRAME 仕様のページでカレンダーを使うとなると、現在 Google Chrome と Opera でしか動作しません。この二つのブラウザはほぼ同じ仕様でカレンダーが表示されますが、FRAME の境界を越える事ができるので、IE の ActiveX の DatePicker の代替えとして利用可能です。 ですが一つ問題があって・・・ このデモページでは対応済ですが、初期値のセット方法として日付フォーマットが -(ハイフン) 区切りである必要がある上に、月と日は2ケタの前ゼロでなければダメです。さらに、表示は /(スラッシュ)区切りで、かつサーバーに送信されると -(ハイフン)区切り になります。 サーバーサイドはそちらで対応すれば良いですが、もともと JavaScript で日付文字列の操作が面倒なので、String オブジェクトと Date オブジェクトに メソッドを追加して使っています。
String.prototype.right = function(n){ var str = this.valueOf(); str = str.substr(str.length-n,n); return str; } String.prototype.zero = function(n){ var strzero = "0000000000000000000"; var str = this.valueOf(); str = strzero + str; return str.right(n); } Date.prototype.datestr = function(sep){ str = this.getFullYear() + sep + (this.getMonth()+1).toString().zero(2) + sep + (this.getDate()).toString().zero(2); return str; }
jQuery もチューニングしていますblur イベントを処理しないと、カレンダーを表示した後、IFRAME 内に移動した時にカレンダーが閉じませんでした。blur イベントを処理してしまうと、カレンダー内部のコントロールをクリックすると閉じてしまったので、IFRAME 側のイベントで対応しました。しかし、IE8 では、IFRAME 側(内部から window)の focus イベントで動作しなかったので、IFRAME を表示しているほうからの focus イベントで対処しています 関連する記事 Google Chrome 専用 jQuery プラグイン : DatePicker( type=date ) の個別機能の設定を行います / 当日セット、キーイベントキャンセル、専用ボタン非表示