这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
关于 iframe 之间的通信问题与自适应高度问题网上有很多,那么这篇文章小编也和大家一起来谈谈 iframe 之间通信问题及 iframe 自适应高度问题,有需要的可以参考借鉴。
首先说明下,iframe 通信 分为:同域通信 和 跨域通信。
一、 同域通信
所谓同域通信是指 http://localhost/demo/iframe/iframeA.html 下的 a.html 页面嵌套 iframe
比如:
这种方法,其中 b 是子页面 B.html 中的一个函数。但是这样调用下有个问题我纠结了很久,就是既然在火狐下报这样的错误, 如下:
- document.getElementById('iframeA').contentWindow.b();
b 不是个函数 但是我在子页面明明定义了这么一个函数,那么为什么会报这样的错误呢?经过仔细分析及 google,发现有这么一个问题需要理解,当 iframe 没有加载完成后 我就去执行这个 js 会报这样的错误,所以就试着在火狐下 用
这个函数 进行测试,果然没有报错,是正确的 所以就确定是这个问题。所以就想写个兼容 IE 和火狐 google 写个函数 来确定 iframe 已经加载完成!,其实给个回调函数来调用我们上面的方法。
- iframe.onload
综合上面的思路 就可以写个这样的代码:
- <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 如下:,我想在 abc 域下的页面 abc.html 访问 def 域下的 def.html 我们都知道由于安全性 游览器的同源策略的限制,js 不能操作页面不同域下 不同协议下 不同端口的页面,所以就要解决跨域访问了,假如父页面 abc.html 页面有个 js 函数:
我想在子页面调用这个函数 还是按照上面的同域方式调用
- function test(){console.log(1);};
这样,通过在火狐下看 已经跨域了 解决的办法是 在各个 js 函数顶部 加一句
- parent.test();
,就可以解决了。
- 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
方法或者 html5 及 flash 等等,但是我觉得下面 iframe 这种方法值得学习下,
- window.name
如下图所示:域 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:我要让你执行你定义好的方法
,并且要用我给你的参数'{"id" : 24}'。response.html 纯粹是负责将
- GetPerson
这个方法名传递给下一位仁兄 proxy.html,而 proxy.html 拿到了
- CallBack
这个方法名就可以执行了,因为 proxy.html 和 request.html 是同域的。
- CallBack
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=j son_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 是 否被改变,但是这样感觉效率很低,还有个方式就是在新的浏览器中通过
事件 (IE8+,Chrome5.0+,Firefox3.6+,Safari5.0+,Opera10.6+)来监听 href 的改变。
- onhashchange
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 自适应高度的问题了。
四、总结
来源: http://www.phperz.com/article/17/0711/332346.html