操作iframe一些方法

510 阅读6分钟
 <iframe id="myframe" src="iframe.html" scrolling="auto" frameborder="0" marginheight="0" marginwidth="0" width="100%" height="800px" style="vertical-align:bottom;"></iframe>
属性    描述
allow                                 允许特定功能的列表,如fullscreen,geolocation等
allowfullscreen                  指定是否允许在iframe中使用全屏模式
allowpaymentrequest       指定是否允许在iframe中进行支付请求
allowtransparency            指定iframe是否可以是透明的
class                                为iframe定义一个或多个类名
frameborder                     指定是否在iframe周围显示边框
height                               指定iframe的高度
importance                       指定iframe对页面内容的重要性
loading                             指定iframe加载时的行为
name                                为iframe定义一个名称
referrerpolicy                    指定如何发送referer HTTP标头
sandbox                            启用iframe的沙盒模式,提高安全性
src                                     指定要在iframe中显示的文档的URL
srcdoc                               在iframe中嵌入HTML代码而不是外部文档
style                                  定义iframe的CSS样式
title                                   为iframe定义一个标题
width                                 指定iframe的宽度

JS获取并操作iframe中元素的方法

如果iframe有跨域的问题,可以使用contentDocument属性获取iframe的document对象,然后操作元素。但是跨域依然存在,像contentDocument.getElementById、querySelector获得元素依然是有问题的。

//.contentDocument 相当于 .contentWindow.document !
document.getElementById('myframe').contentWindow.document.getElementById('元素的ID')
// 假设iframe的id是"myframe"
var iframeDocument = document.getElementById('myframe').contentDocument || document.getElementById('myframe').contentWindow.document;
var elementInsideIframe = iframeDocument.getElementById('elementId'); // 'elementId'是你想要控制的元素的ID

// 例如,改变元素的样式
elementInsideIframe.style.color = 'red';

检测iframe加载完成

document.getElementById('myframe').onload = function() {
    console.log('Iframe is loaded!');
};

iframe 设置本地缓存

只能同域名设置,跨域设置缓存,存在问题。

// 主页面->设置localStorage数据
window.onload = function() {
    var iframe = document.getElementById('myframe');
    var iframeWindow = iframe.contentWindow;
    iframeWindow.localStorage.setItem('key', 'value');
};
//iframe页面->获取localStorage数据
window.onload = function() {
    var value = localStorage.getItem('key');
    console.log('The value of key is:', value); // 输出: The value of key is: value
};

iframe页面通讯

父页面和子页面通过postMessage进行通信,设置iframe的高度。

// iframe 域 /////////////////////////////////////////////
const sendHeight = ()=>{
    if(window.parent){
        const firstElement = document.querySelector('.admit-question-box');
        if(!firstElement)return;
        let mH = firstElement.scrollHeight + 200;
        window.parent.postMessage({ height: mH }, '*'); // 发送高度父容器
    }
}
//接收父容器消息
window.addEventListener('message', function(event) {
    nextTick(() => {
        sendHeight();
    })
});


// 主页面 /////////////////////////////////////////////
const myframe = document.getElementById('myframe');
myframe.onload = function() {
    myframe.contentWindow.postMessage('height', '*');
};
window.addEventListener('message', function(event) {
    myframe.height = event.data.height;
});

document.domain + iframe跨域

此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。

//1.父窗口:(http://www.domain.com/a.html)
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
    document.domain = 'domain.com';
    var user = 'admin';
</script>

//2.子窗口:(http://child.domain.com/b.html)
<script>
    document.domain = 'domain.com';
    // 获取父窗口中变量
    alert('get js data from parent ---> ' + window.parent.user);
</script>

window.name属性详解

window自身就带有name这个属性,在控制台输入window可以可以看到。window.name直译过来是窗口名字,主要用于为超链接和表单设置目标(targets)。 该属性只能保存字符串,如果写入的值不是字符串,会自动转成字符串。只要浏览器窗口不关闭,这个属性是不会消失的。 举例,访问a.com时,该页面的脚本设置了window.name,接下来在同一个窗口里面载入了b.com,新页面的脚本可以读到上一个网页设置的 window.name。页面刷新也是这种情况。一旦浏览器窗口关闭后,该属性保存的值就会消失,因为这时窗口已经不存在了。 . 第一个页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JSdemo1</title>
</head>
<body>
    <a href="./demo2.html" target="hello world">跳转</a>
</body>
</html> 

. 第二个页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JSdemo2</title>
    <script>
        document.write( window.name + "<br>" + name )
        //这里我们就可以看出,第一个网页的a标签通过target属性将值赋值给第二个窗口的name属性,这样第二个网页的name属性就有值了。
    </script>
</head>
<body>
</body>
</html>

window.name属性,实现跨域

. 第一个页面放在域名localhost下

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>页面一</title>
</head>
<body>
    <h1>页面一</h1>
    <script>
        var iframe = document.createElement('iframe');//工具人
        iframe.style.display = "none";//工具人隐藏在背后默默付出
        var flag = false;
        iframe.onload = function () {
            if ( flag ) {
                var data = iframe.contentWindow.name;//contentWindow.name可以拿到iframe的窗口name值
                console.log(data);
                iframe.contentWindow.close();//关闭隐藏的页面
                document.body.removeChild(iframe);//删除隐藏的页面
            } else {
                flag = true;
                iframe.contentWindow.location = 'http://localhost/demo2.html';//这里因为浏览器同源策略,需要将链接改成与页面一同源的页面(也就是页面二),这里会再次触发load事件
            }
        }
        iframe.src = 'http://data/data.html';//跨域,这里窗口已经拿到name,所以上面更换地址后name的值依旧存在
        document.body.appendChild(iframe);
    </script>
</body>
</html>

. 第二个页面是空页面,也是在localhost域名下

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>页面二</title>
</head>
<body>
</body>
</html>

. 第三个页面是数据页面,放在data域名下

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>data</title>
</head>
<body>
    <h1>数据</h1>
<script>
    window.name = '{data:"数据"}';//将数据存到window.name里
</script>
</body>
</html>

js跨域问题的解决方案

  1. JSONP解决方案

JSONP是一种利用script标签实现跨域请求的方法。通过在请求URL中添加callback参数,服务器返回一段执行该参数函数的JavaScript代码,从而实现跨域请求并获取数据。

function handleResponse(data) {
  // 在此处理获取到的数据
}
var script = document.createElement('script');
script.src = 'http://example.com/data?callback=handleResponse';
document.body.appendChild(script);

example.com/data?callba… 示例代码 handleResponse({"name":"John","age":30});

<?php
// 假设通过GET参数接收回调函数名称
$callback = $_GET['callback'];
// 假设有一些数据要返回
$data = array('name' => 'John', 'age' => 30);
// 输出JavaScript代码,调用回调函数
echo $callback . '(' . json_encode($data) . ');';
?>
  1. CORS解决方案

CORS(跨域资源共享)是一种服务器端解决跨域问题的机制。在服务器端设置响应头中的Access-Control-Allow-Origin字段,允许指定的域名或所有域名进行跨域请求。

const http = require('http');
 
http.createServer((req, res) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://example.com'); // 允许 http://example.com 域名跨域请求
  // 处理请求并返回数据
}).listen(8080);
  1. 代理服务器解决方案

通过在本地部署一个代理服务器,将同源策略限制的请求发送到该代理服务器上,再由代理服务器转发请求到目标服务器,这样就实现了跨域请求。

  1. document.domain + iframe跨域

此方案仅限主域相同,子域不同的跨域应用场景。通过 iframe 是浏览器非同源标签,加载内容中转,传到当前页面的属性中。实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。

//1.)父窗口:(http://www.domain.com/a.html)
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script> 
    document.domain = 'domain.com';
    var user = 'admin'; 
</script>

//2.)子窗口:(http://child.domain.com/b.html)
<script> 
    document.domain = 'domain.com';
    // 获取父窗口中变量
    alert('get js data from parent ---> ' + window.parent.user); 
</script>
  1. postMessage跨域
  2. WebSocket 协议跨域

Document.referrer

是一个 URI,当前页面就是从这个 URI 所代表的页面跳转或打开的。如果用户直接打开了这个页面(不是通过页面跳转,而是通过地址栏或者书签等打开的),则该属性为空字符串。由于该属性只是返回一个字符串,所以不能够通过该属性引用页面的 DOM。 在 iframe 中,Document.referrer 会初始化为父窗口 Window.location 的 href。

无法获取 referrer 信息的情况
1、直接在浏览器中输入地址
2、使用location.reload()刷新(location.href或者location.replace()刷新有信息)
3、在微信对话框中,点击进入微信自身浏览器
4、扫码进入微信或QQ的浏览器
5、直接新窗口打开一个页面
6、从https的网站直接进入一个http协议的网站(Chrome下亲测)
7、a标签设置rel="noreferrer"(兼容IE7+)
8、meta标签来控制不让浏览器发送referer
9、点击 flash 内部链接
10、Chrome4.0以下,IE 5.5+以下返回空的字符串
11、使用 修改 Location 进行页面导航的方法,会导致在IE下丢失 referrer,这可能是IE的一个BUG
跨域
12、<meta content="never" name="referrer">