JS解决iframe之间通信和自适应高度的问题

首先说明下,iframe通信 分为:同域通信 和 跨域通信。

一、 同域通信

所谓同域通信是指 http://localhost/demo/iframe/iframeA.html 下的a.html页面嵌套 iframe

比如: <iframe src="http://localhost/demo/iframe/iframeB.html" id="iframeA" name="iframeA">的B.html页面,这两个页面数据进行通信,比如我想在父页面A.html 调用子页面当中的函数 我们很容易想到或者google下 document.getElementById('iframeA').contentWindow.b(); 这种方法,其中b 是子页面B.html中的一个函数。但是这样调用下有个问题我纠结了很久,就是既然在火狐下报这样的错误, 如下:

b不是个函数 但是我在子页面明明定义了这么一个函数,那么为什么会报这样的错误呢?经过仔细分析及google,发现有这么一个问题需要理解,当iframe没有加载完成后 我就去执行这个js会报这样的错误,所以就试着在火狐下 用iframe.onload 这个函数 进行测试,果然没有报错,是正确的 所以就确定是这个问题。所以就想写个兼容IE和火狐 google写个函数 来确定iframe已经加载完成!,其实给个回调函数来调用我们上面的方法。

综合上面的思路 就可以写个这样的代码:

<iframe src="http://localhost/demo/iframe/iframeB.html" id="iframeA" name="iframeA"></iframe>
 <div id="topName">topNddddddddddddddddame</div>
 <script>
  function A(){
  alert("A");
 }
 var iframe = document.getElementById('iframeA');

 iframeIsLoad(iframe,function(){
  var obj = document.getElementById('iframeA').contentWindow;
  obj.b();
 });

 function iframeIsLoad(iframe,callback){
 if(iframe.attachEvent) {

  iframe.attachEvent('onload',function(){
  callback && callback();
  });
 }else {
  iframe.onload = function(){
  callback && callback();
  }
 }
 }

 </script>

B.html 代码如下:

var b = function(){
  alert("B");
 }

子页面调用父页面的函数很简单,只要这样搞下就ok了,window.parent.A();

子页面取父页面元素的值: window.parent.document.getElementById("topName").innerHTML等方法。

二: iframe跨域通信。

iframe跨域访问一般分为2种情况,第一种是同主域,不同子域的跨域。 第二种是:不同主域跨域。

1、 是同主域下面,不同子域之间的跨域;可以通过document.domain 来设置相同的主域来解决。

假如现在我有个域 abc.example.com 下有个页面叫abc.html, 页面上嵌套了一个iframe 如下:<iframe src="http://def.example.com/demo/def.html"  id="iframe2" style="display:none;"></iframe>,我想在abc域下的页面abc.html 访问 def域下的def.html  我们都知道由于安全性 游览器的同源策略的限制,js不能操作页面不同域下 不同协议下 不同端口的页面,所以就要解决跨域访问了,假如父页面abc.html 页面有个js函数:function test(){console.log(1);}; 我想在子页面调用这个函数 还是按照上面的同域方式调用 parent.test();这样,通过在火狐下看 已经跨域了 解决的办法是 在各个js函数顶部 加一句 document.domain = 'example.com',就可以解决了。

abc.html代码如下:

<iframe src="http://def.example.com/demo/def.html" id="iframe2" style="display:none;"></iframe>

// 跨域 子页调用父页的 函数 (假设是下面test函数)
document.domain = 'example.com';
function test(){console.log(1);};

def.html代码如下:

/*
 * 子页调用父页的方法
 */
document.domain = 'example.com';
//window.top.test();
window.parent.test();

还是这两个页面 我想父页调用子页 如下方法:

a.html代码如下:

/*
 * 跨域 父页想调用子页的的函数
 */
document.domain = 'example.com';
var iframe = document.getElementById('iframe2');
iframeIsLoad(iframe,function(){
 var obj = iframe.contentWindow;
  obj.child();
});
function iframeIsLoad(iframe,callback){
 if(iframe.attachEvent) {
  iframe.attachEvent('onload',function(){
  callback && callback();
  });
 }else {
  iframe.onload = function(){
  callback && callback();
  }
 }
 }

假如现在def.html页面有个child函数 代码如下:

document.domain = 'example.com';
function child(){console.log('我是子页');}

就可以跨域调用了 不管是子页面调用父页面 还是父页面调用子页面。一切ok!

2、 是不同主域跨域;

虽然google有几种方法关于不同主域上的跨域问题 有通过location.hash方法或者window.name方法或者html5及flash等等,但是我觉得下面iframe这种方法值得学习下,

如下图所示:域a.com的页面request.html(即http://a.com/demo/ajax/ajaxproxy/request.html)里面嵌套了一个iframe指向域b.com(http://b.com/demo/ajax/ajaxproxy/response.html)的response.html,而response.html里又嵌套了域a.com的proxy.html。

思路:要实现a.com域下的request.html页面请求域b.com下的process.php,可以将请求参数通过url传给response.html,由response.html向process.php发起真正的ajax请求(response.html与process.php都属于域b.com),然后将返回的结果通过url传给proxy.html,最后由于proxy.html和request.html是在同个域下,所以可以在proxy.html利用window.top 将结果返回在request.html完成真正的跨域。

ok, 先看看页面结构

a.com域下有:

request.html

proxy.html

b.com域下有:

response.html

process.php

先来看看request.html页面如下:

<!DOCTYPE HTML>
<html>
 <head>
 <title> New Document </title>
 </head>

 <body>
 <p id="result">这里将会填上响应的结果</p>
 <a id="sendBtn" href="javascript:void(0)">点击,发送跨域请求</a>
 <iframe id="serverIf" style="display:none"></iframe>

 <script>
 document.getElementById('sendBtn').onclick = function() {
  var url = 'http://b.com/demo/ajax/ajaxproxy/reponse.html',
  fn = 'GetPerson',  //这是定义在response.html的方法
  reqdata = '{"id" : 24}', //这是请求的参数
  callback = "CallBack"; //这是请求全过程完成后执行的回调函数,执行最后的动作

  CrossRequest(url, fn, reqdata, callback); //发送请求
 }

 function CrossRequest(url,fn,reqdata,callback) {
  var server = document.getElementById('serverIf');
  server.src = url + '?fn=' +encodeURIComponent(fn) + "&data=" +encodeURIComponent(reqdata) + "&callback="+encodeURIComponent(callback);
 }
 //回调函数
 function CallBack(data) {
  var str = "My name is " + data.name + ". I am a " + data.sex + ". I am " + data.age + " years old.";
  document.getElementById("result").innerHTML = str;
 }
 </script>
 </body>
</html>

  这个页面其实就是要告诉response.html:我要让你执行你定义好的方法GetPerson,并且要用我给你的参数'{"id" : 24}'。response.html纯粹是负责将CallBack这个方法名传递给下一位仁兄proxy.html,而proxy.html拿到了CallBack这个方法名就可以执行了,因为proxy.html和request.html是同域的。

response.html代码如下:    

<!DOCTYPE HTML>
<html>
 <head>
 <title> New Document </title>
 </head>

 <body>
 <iframe id="proxy"></iframe>
 <script>
 // 通用方法 ajax请求
 function _request (reqdata,url,callback) {
  var xmlhttp;
  if(window.XMLHttpRequest) {
  xmlhttp = new XMLHttpRequest();
  }else {
  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  }

  xmlhttp.onreadystatechange = function(){
  if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
   var data = xmlhttp.responseText;
   callback(data);
  }
  }
  xmlhttp.open('POST',url);
  xmlhttp.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  xmlhttp.send(reqdata);
 }

 // 通用方法 获取url参数
 function _getQuery(key) {
  var query = location.href.split('?')[1],
  value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]);
  return value;
 }

 //向process.php发送ajax请求
 function GetPerson(reqdata,callback) {
  var url = 'http://b.com/demo/ajax/ajaxproxy/process.php';
  var fn = function(data) {
  var proxy = document.getElementById('proxy');
  proxy.src = "http://a.com/demo/ajax/ajaxproxy/Proxy.html?data=" + encodeURIComponent(data) + "&callback=" + encodeURIComponent(callback);
  };
  _request(reqdata, url, fn);
 }

 (function(){
  var fn = _getQuery('fn'),
  reqdata = _getQuery("data"),
  callback = _getQuery("callback");
  eval(fn + "('" + reqdata +"', '" + callback + "')");
 })();
 </script>
 </body>
</html>

这里其实就是接收来自request.html的请求得到请求参数和方法后向服务器process.php发出真正的ajax请求,然后将从服务器返回的数据以及从request.html传过来的回调函数名传递给proxy.html。 

接下来看看php代码如下,其实就是想返回一个json数据:

<?php
 $data = json_decode(file_get_contents("php://input"));
 header("Content-Type: application/json; charset=utf-8");
 echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}');
?>

最后就是proxy.html代码:

<!DOCTYPE HTML>
<html>
 <head>
 <title> New Document </title>
 </head>

 <body>
 <script>
  function _getUrl(key) {//通用方法,获取URL参数
   var query = location.href.split("?")[1],
  value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]);
   return value;
  }
  (function() {
  var callback = _getUrl("callback"),
   data = _getUrl("data");
  eval("window.top." + decodeURIComponent(callback) + "(" + decodeURIComponent(data) + ")");
  })();
 </script>
 </body>
</html>

  这里也是最后一步了,proxy终于拿到了request.html透过response.html传过来的回调函数名以及从response.html直接传过来的响应数据,利用window.top执行request.html里定义的回调函数。

三、iframe高度自适应的问题。

iframe高度自适应分为2种,一种是同域下自适应  另外一种是跨域下自适应,下面我们来看看同域下iframe高度自适应的问题。

1.同域下iframe高度自适应的问题:

思路:获取被嵌套iframe元素,通过JavaScript取得被嵌套页面最终高度,然后在主页面进行设置来实现。

假如我们demo有iframe1.html和iframe2.html

下面贴上iframe1.html代码如下:

<!DOCTYPE HTML>
<html>
 <head>
 <title> New Document </title>
 <style>
 *{margin:0;padding:0;}
 </style>
 </head>

 <body>
 <iframe src="http://a.com/demo/ajax/iframeheight/iframe2.html" style="width:100%;border:1px solid #333;" frameborder="0" id="iframe"></iframe>

 <script>
 window.onload = function() {
  var iframeid = document.getElementById('iframe');
  if(iframeid && !window.opera) {
  if(iframeid.contentDocument && iframeid.contentDocument.body.offsetHeight) {
   iframeid.height = iframeid.contentDocument.body.offsetHeight;
  }else if(iframeid.Document && iframeid.Document.body.scrollHeight){
   iframeid.height = iframeid.Document.body.scrollHeight;
  }
  }
 }
 </script>
 </body>
</html>

iframe2.html

<!DOCTYPE HTML>
<html>
 <head>
 <title> New Document </title>
 <style>
 *{margin:0;padding:0;}
 </style>
 </head>

 <body>
 <div style="height:500px;"></div>
 </body>
</html>

就可以动态设置iframe1页面的高度为iframe2的高度了。

 2. 跨域下iframe高度自适应的问题。

首先我们知道iframe跨域我们是不能用上面js方式来控制了,所以我们只能用个中间键 我们可以在a.com域下iframe1.html页面嵌套一个b.com域下的iframe2.html页面,然后我在iframe2.html页面嵌套个和iframe1.html相同域的iframe3.html页面了,这样的话 iframe1.html和iframe3.html就可以无障碍的进行通信了,因为页面iframe2.html嵌套iframe3.html,所以iframe2.html可以改写iframe3.html的href值。

   iframe1中的内容:

iframe1.html内容主要接受iframe3.html页面传过来的内容并且去完成相应的操作。iframe1.html代码如下:

<iframe src="http://b.com/demo/ajax/iframeheight/iframe2.html" style="width:400px;height:200px;" id="iframe"></iframe> 

<script>
 var ifr_el = document.getElementById("iframe");
 function getIfrData(data){
 ifr_el.style.height = data+"px";
 }
</script>

iframe2.html中的内容:

iframe2.html内容是怎么把值传给iframe3.html页面,刚才说了是将值传递到iframe3.html页面的href中,所以只要修改iframe的src就可以,因为不用刷新C页面,所以可以用过hash的方式传递给iframe3.html页面.iframe2.html代码如下:

<!DOCTYPE HTML>
<html>
 <head>
 <title> New Document </title>
 <style>
 *{margin:0;padding:0;}
 </style>
 </head>

 <body>
 <iframe id="iframe" src="http://a.com/demo/ajax/iframeheight/iframe3.html" width="0" height="230px"></iframe>

 <script>
 var oldHeight = 0,
  ifr_el = document.getElementById("iframe");

 t && clearInterval(t);
 var t = setInterval(function(){
  var height = document.body.scrollHeight;
  if(oldHeight != height) {
  oldHeight = height;
  ifr_el.src += '#' +oldHeight;
  }
 },200);
 </script>
 </body>
</html>

可以看到 默认情况下 iframe1.html 页面我给iframe2.html的高度是200像素 但是在iframe2.html我给iframe3.html高度是230像素,那么正常情况下是有滚动条的,那么现在我是想在iframe2.html获取滚动条的高度,把高度传给通过iframe3.html的src里面去,然后在iframe3.html页面里获取这个高度值 传给iframe1.html(因为iframe1.html和iframe3.html是同域的),所以iframe1.html能取到这个高度值,再设置下本身的高度就是这个值就ok了。

iframe3.html页面的唯一功能就是接收iframe2.html页面通过href传进来的值并且传递给iframe1.html页面,可到iframe2.html页面传来的值可以通过一个定时器不停去查看location.href是 否被改变,但是这样感觉效率很低,还有个方式就是在新的浏览器中通过onhashchange事件 (IE8+,Chrome5.0+,Firefox3.6+,Safari5.0+,Opera10.6+)来监听href的改变。

iframe3.html代码如下:

<script>
 var oldHeight = 0;

 t && clearInterval(t);
 var t = setInterval(function(){
 var height = location.href.split('#')[1];
 if(height && height != oldHeight) {
  oldHeight = height;
  if(window.parent.parent.getIfrData) {
  window.parent.parent.getIfrData(oldHeight);
  }
 }
 },200);
 </script>

这样就可以解决通过跨域实现iframe自适应高度的问题了。

四、总结

以上就是本文的全部内容了,希望对大家的学习工作能有所帮助。如果有疑问可以留言讨论。

(0)

相关推荐

  • jQuery简单实现iframe的高度根据页面内容自适应的方法

    本文实例讲述了jQuery简单实现iframe的高度根据页面内容自适应的方法.分享给大家供大家参考,具体如下: 方式1: //注意:下面的代码是放在和iframe同一个页面中调用 $("#iframeId").load(function () { var mainheight = $(this).contents().find("body").height() + 30; $(this).height(mainheight); }); 方式2: //注意:下面的代码

  • JS实现iframe自适应高度的方法示例

    本文实例讲述了JS实现iframe自适应高度的方法.分享给大家供大家参考,具体如下: <iframe id="mainFrame" name="mainFrame" src="/zwgk/hsearchview" width="740" frameborder="0" scrolling="no" scrolling="no" frameborder="

  • javascript 中iframe高度自适应(同域)实例详解

    javascript 中iframe高度自适应(同域) 今天解决了iframe高度自适应的问题,不过这只是同域下的页面嵌入,以下是代码: function SetCwinHeight(){ var iframeid = document.getElementById("frame"); //frame是iframe的id if (document.getElementById) { if (iframeid && !window.opera) { if (iframei

  • 使用jQuery不判断浏览器高度解决iframe自适应高度问题

    这里介绍两个超级简单的方法,不用写什么判断浏览器高度.宽度啥的. 下面的两种方法自选其一就行了.一个是放在和iframe同页面的,一个是放在test.html页面的. 注意别放错了地方. iframe的代码中,注意要写ID,没有ID查找不到 复制代码 代码如下: <iframe src="test.html" id="main" width="700" height="300" frameborder="0&q

  • jsp页面iframe高度自适应的js代码

    以下操作写在body里面,form表单外 <iframe id="agentFrame" name="agentFrame" src="" width="0" height="0" style="display:none;" ></iframe> <script type="text/javascript"> function se

  • iframe高度自适应及隐藏滚动条的实例详解

    iframe高度自适应及隐藏滚动条的实例详解 在工作中,我们可能会遇到自己公司和其他的公司达成合作关系,从而共同开发某个项目.而这时候,我们可能就需要在自己的网站上嵌入别人做好的页面.而这种情况下,我们一般都会选择去使用iframe达到我们的目的.但是iframe用起来,真的是让人头痛,高度无法控制,难看的滚动条等等,下面我分享一下自己在处理iframe时的一些心得. 高度自适应 <iframe src="http://huichang.qunar.com/huiQunar" i

  • js实现iframe自动自适应高度的方法

    本文实例讲述了js实现iframe自动自适应高度的方法.分享给大家供大家参考.具体如下: 在编写网页的时候,很多时候要用到自动伸缩iframe高度 ,假如ifram中嵌入的是一个列表,那么增加数据后,刷新列表,iframe高度会自动伸长.删除数据后,iframe高度要自动缩短. 将下一段代码拷贝到iframe所在那个html或者jsp页面.在</html>标签后,调用此函数即可. <script type="text/javascript"> autoAdjus

  • JS实现iframe自适应高度的方法(兼容IE与FireFox)

    本文实例讲述了JS实现iframe自适应高度的方法.分享给大家供大家参考,具体如下: 之前一直被iframe自适应高度的问题困扰,很多JS代码在FF里面似乎就变成哑巴了.后来下面这段代码终于被我从万千号称兼容FF的代码堆中翻了出来.我已经用过了,真的好用.尤其是对于我这样的JS水平较低(真不好意思)的人来说,这段代码简单易懂,方便修改,只要把下面的代码复制粘贴到iframe所在页面的<body>标签里面,并且修改一下ID名就行了(注意,要修改的地方有两个,位置在代码中有说明). 向原创这段代码

  • JS解决iframe之间通信和自适应高度的问题

    首先说明下,iframe通信 分为:同域通信 和 跨域通信. 一. 同域通信 所谓同域通信是指 http://localhost/demo/iframe/iframeA.html 下的a.html页面嵌套 iframe 比如: <iframe src="http://localhost/demo/iframe/iframeB.html" id="iframeA" name="iframeA">的B.html页面,这两个页面数据进行通信

  • Iframe实现跨浏览器自适应高度解决方法

    本文以实例形式讲述了Iframe实现跨浏览器自适应高度解决方法,非常具有实用价值.分享给大家供大家参考之用.具体方法如下: 该方法使用了jQuery,因此需要在iframe的src页面里面引入jQuery. 父页面里面相对简单一点,主要包含以下代码: <iframe id="if1" scrolling="no" src="2.html"></iframe> 在iframe的src页面里面代码如下: <script

  • 如何实现iframe(嵌入式帧)的自适应高度

    好几次看到有人提问问到如何实现 iframe 的自适应高度,能够随着页面的长度自动的适应以免除页面和 iframe 同时出现滚动条的现象,刚好我在工作中也碰到了类似问题,于是上网翻查,东抄抄西看看,弄出来这么一个函数,贴到页面里面就能用了.不敢独享,大家要是觉得有用,欢迎使用 源代码如下 复制代码 代码如下: <script type="text/javascript">  //** iframe自动适应页面 **// //输入你希望根据页面高度自动调整高度的iframe的

  • javascript 装载iframe子页面,自适应高度

    假设主页面有一个div,里面放置一个iframe 复制代码 代码如下: <div id="frameBox"> <iframe id="frameWin" src="1.html" name="opWin" style="width:100%; height:100% " frameborder="0" scrolling="no"></

  • JS中Iframe之间传值及子页面与父页面应用

    在js中,我们时常用到用iframe做系统框架,在子页面也,父页面之间的值传递是一个问题,下面是js获取父窗体和子窗体的对象js: 1.在iframe子页面中获取父页面的元素: a>window.parent.document这个是获取父页面document中的对象: b>如果要获取父页面js中的方法:window.parent.xxxx():xxxx()为方法: 2.在父页面中获取iframe子页面中的元素: a> 复制代码 代码如下: var child = document.get

  • JS中Iframe之间传值的方法

    1.在iframe子页面中获取父页面的元素: a>window.parent.document这个是获取父页面document中的对象: b>如果要获取父页面js中的方法:window.parent.xxxx():xxxx()为方法: 2.在父页面中获取iframe子页面中的元素: a> var child = document.getElementByIdx_x("mainFrame").contentWindow;//mainFrame这个id是父页面iframe

  • 兼容主流浏览器的iframe自适应高度js脚本

    兼容主流浏览器的 Iframe 自适应高度,js脚本如下: 复制代码 代码如下: //iframe 高度自适应 function iframeAutoFit(iframeObj) { setTimeout(function () { if (!iframeObj) return; iframeObj.height = (iframeObj.Document ? iframeObj.Document.body.scrollHeight : iframeObj.contentDocument.bod

随机推荐