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
等方法。function test(){console.log(1);};
我想在子页面调用这个函数 还是按照上面的同域方式调用 parent.test();
这样,通过在火狐下看 已经跨域了 解决的办法是 在各个js函数顶部 加一句 document.domain = "example.com"
,就可以解决了。<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();还是这两个页面 我想父页调用子页 如下方法:
/* * 跨域 父页想调用子页的的函数 */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!
location.hash
方法或者window.name
方法或者html5及flash等等,但是我觉得下面iframe这种方法值得学习下,
思路:要实现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是同域的。<!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$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里定义的回调函数。
<!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的高度了。
<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中的内容:
<!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了。
onhashchange
事件 (IE8+,Chrome5.0+,Firefox3.6+,Safari5.0+,Opera10.6+)来监听href的改变。<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自适应高度的问题了。