جاوااسکریپت - تغییر اندازه یک iframe بر اساس محتوا


من روی یک برنامه شبیه iGoogle کار میکنم. محتوای برنامههای دیگر (در دامنههای دیگر) با استفاده از iframes نمایش داده میشود.

چگونه میتوانم اندازه فریمهای درونخطی را طوری تغییر دهم که با ارتفاع محتوای فریمها هماهنگ شود؟

من سعی کردهام جاوااسکریپتی که گوگل استفاده میکند را رمزگشایی کنم اما مبهم است و جستجو در وب تا کنون بینتیجه بوده است.

بهروزرسانی: لطفاً توجه داشته باشید که محتوا از دامنههای دیگر بارگذاری میشود، بنابراین سیاست همانمبدا اعمال میشود.

پاسخ شماره ۱

ما این نوع مشکل را داشتیم، اما کمی برعکس وضعیت شما - ما محتوای iframe شده را به سایتهای دیگر در دامنههای دیگر ارائه میدادیم، بنابراین سیاست مبدأ یکسان نیز یک مسئله بود. پس از ساعتها جستجو در گوگل، نهایتاً یک راهحل (تا حدی..) قابل استفاده پیدا کردیم که ممکن است بتوانید آن را با نیازهای خود تطبیق دهید.

راهی برای دور زدن سیاست منبع یکسان وجود دارد، اما این کار نیاز به تغییراتی در محتوای iframe شده و صفحه فریمبندی دارد، بنابراین اگر توانایی درخواست تغییرات در هر دو طرف را ندارید، متأسفانه این روش برای شما مفید نخواهد بود.

یک مشکل مرورگر وجود دارد که به ما اجازه میدهد از سیاست منبع یکسان عبور کنیم - جاوااسکریپت میتواند با صفحات در دامنه خود یا با صفحاتی که درون iframe قرار داده است ارتباط برقرار کند، اما هرگز با صفحاتی که در آنها فریم شده است، ارتباط ندارد، به عنوان مثال اگر شما داشته باشید:

 www.foo.com/home.html, which iframes
 |-> www.bar.net/framed.html, which iframes
     |-> www.foo.com/helper.html

سپس home.html میتواند با framed.html (درون قاب iframed) و helper.html (همین دامنه) ارتباط برقرار کند.

 Communication options for each page:
 +-------------------------+-----------+-------------+-------------+
 |                         | home.html | framed.html | helper.html |
 +-------------------------+-----------+-------------+-------------+
 | www.foo.com/home.html   |    N/A    |     YES     |     YES     |
 | www.bar.net/framed.html |    NO     |     N/A     |     YES     |
 | www.foo.com/helper.html |    YES    |     YES     |     N/A     |
 +-------------------------+-----------+-------------+-------------+

framed.html میتواند پیامهایی به helper.html (درون iframe) ارسال کند اما نمیتواند به home.html (فرزند نمیتواند با والد در دامنه دیگر ارتباط برقرار کند) ارسال کند.

نکته کلیدی این است که helper.html میتواند پیامها را از framed.html دریافت کند و همچنین میتواند با home.html ارتباط برقرار کند.

بنابراین اساساً، وقتی framed.html بارگذاری میشود، ارتفاع خود را محاسبه میکند، به helper.html میگوید، که پیام را به home.html منتقل میکند، که سپس میتواند iframe که framed.html در آن قرار دارد را تغییر اندازه دهد.

سادهترین راهی که ما برای ارسال پیامها از framed.html به helper.html پیدا کردیم، از طریق یک آرگومان URL بود. برای انجام این کار، framed.html یک iframe دارد که src='' مشخص شده است. وقتی onload آن اجرا میشود، ارتفاع خودش را محاسبه میکند و در این نقطه src iframe را روی helper.html?height=N تنظیم میکند

در اینجا یک توضیح وجود دارد درباره اینکه فیسبوک چگونه آن را مدیریت میکند، که ممکن است کمی واضحتر از توضیح من در بالا باشد!


کد

در www.foo.com/home.html، کد جاوااسکریپت زیر مورد نیاز است (اتفاقاً این میتواند از یک فایل .js در هر دامنهای بارگذاری شود..):

<script>
  // Resize iframe to full height
  function resizeIframe(height)
  {
    // "+60" is a general rule of thumb to allow for differences in
    // IE & and FF height reporting, can be adjusted as required..
    document.getElementById('frame_name_here').height = parseInt(height)+60;
  }
</script>
<iframe id='frame_name_here' src='http://www.bar.net/framed.html'></iframe>

در www.bar.net/framed.html:

<body onload="iframeResizePipe()">
<iframe id="helpframe" src='' height='0' width='0' frameborder='0'></iframe>

<script type="text/javascript">
  function iframeResizePipe()
  {
     // What's the page height?
     var height = document.body.scrollHeight;

     // Going to 'pipe' the data to the parent through the helpframe..
     var pipe = document.getElementById('helpframe');

     // Cachebuster a precaution here to stop browser caching interfering
     pipe.src = 'http://www.foo.com/helper.html?height='+height+'&cacheb='+Math.random();

  }
</script>

محتویات www.foo.com/helper.html:

<html> 
<!-- 
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content 
--> 
  <body onload="parentIframeResize()"> 
    <script> 
      // Tell the parent iframe what height the iframe needs to be
      function parentIframeResize()
      {
         var height = getParam('height');
         // This works as our parent's parent is on our domain..
         parent.parent.resizeIframe(height);
      }

      // Helper function, parse param from request string
      function getParam( name )
      {
        name = name.replace(/[\[]/,""[").replace(/[\]]/,""]");
        var regexS = "[\\?&]"+name+"=([^&#]*)";
        var regex = new RegExp( regexS );
        var results = regex.exec( window.location.href );
        if( results == null )
          return "";
        else
          return results[1];
      }
    </script> 
  </body> 
</html>

پاسخ شماره ۲

اگر نیازی به مدیریت محتوای iframe از یک دامنه دیگر ندارید، این کد را امتحان کنید، این مشکل را به طور کامل حل میکند و ساده است:

<script language="JavaScript">
<!--
function autoResize(id){
    var newheight;
    var newwidth;

    if(document.getElementById){
        newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
        newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
    }

    document.getElementById(id).height= (newheight) + "px";
    document.getElementById(id).width= (newwidth) + "px";
}
//-->
</script>

<iframe src="usagelogs/default.aspx" width="100%" height="200px" id="iframe1" marginheight="0" frameborder="0" onLoad="autoResize('iframe1');"></iframe>

پاسخ شماره ۳

https://developer.mozilla.org/en/DOM/window.postMessage

window.postMessage()

window.postMessage یک روش برای فعال کردن امن ارتباط بین مبداهای مختلف است. معمولاً، اسکریپتها در صفحات مختلف تنها زمانی میتوانند به یکدیگر دسترسی پیدا کنند که و فقط اگر صفحاتی که آنها را اجرا کردهاند در موقعیتهایی با همان پروتکل (معمولاً هر دو http)، شماره پورت (80 به عنوان پیشفرض برای http) و میزبان باشند (با در نظر گرفتن این که document.domain توسط هر دو صفحه به یک مقدار تنظیم شده باشد). window.postMessage یک مکانیزم کنترلشده فراهم میکند تا این محدودیت را به روشی امن که در صورت استفاده صحیح ایمن است، دور بزند.

خلاصه

window.postMessage، هنگام فراخوانی، باعث میشود یک MessageEvent در پنجره هدف ارسال شود زمانی که هر اسکریپت معلقی که باید اجرا شود تکمیل شد (مثلاً پردازشگرهای رویداد باقیمانده اگر window.postMessage از یک پردازشگر رویداد فراخوانی شود، تایماوتهای معلق قبلاً تنظیم شده، و غیره). MessageEvent دارای نوع message است، یک ویژگی data که به مقدار رشتهای آرگومان اولی که به window.postMessage داده شده تنظیم میشود، یک ویژگی origin که متناظر با مبدا سند اصلی در پنجرهای است که window.postMessage را در زمان فراخوانی آن فراخوانی کرده است، و یک ویژگی source که همان پنجرهای است که window.postMessage از آن فراخوانی شده. (سایر ویژگیهای استاندارد رویدادها نیز با مقادیر مورد انتظار خود موجود هستند.)

کتابخانه iFrame-Resizer از postMessage برای نگه داشتن اندازه یک iFrame متناسب با محتوا استفاده میکند، همراه با MutationObserver برای شناسایی تغییرات در محتوا و به jQuery وابسته نیست.

https://github.com/davidjbradshaw/iframe-resizer

jQuery: خوبیهای اسکریپتنویسی بین دامنهای

http://benalman.com/projects/jquery-postmessage-plugin/

دارای نسخه نمایشی تغییر اندازه پنجره iframe...

http://benalman.com/code/projects/jquery-postmessage/examples/iframe/

این مقاله نشان میدهد چگونه وابستگی به jQuery را حذف کنیم... علاوه بر این، دارای اطلاعات مفید زیادی و لینک به راهحلهای دیگر است.

http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/

مثال ساده...

http://onlineaspect.com/uploads/postmessage/parent.html

پیشنویس کاری HTML 5 درباره window.postMessage

http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages

جان رسیگ درباره پیامرسانی میان پنجرهها

http://ejohn.org/blog/cross-window-messaging/