简介
在开发的过程中,即使在现代浏览器的中,有时还是会遇到使用iframe的时候,虽然iframe在性能和安全方面,有很多诟病,但是它还是有一些用途,能够解决一些棘手的问题。本身将会列举几个用于。
iframe是什么呢?
iframe
全称inline frame
。顾名思义,嵌入在一个HTML
上下文中的窗口。尽管是嵌入到另一个文档中的上下文,但iframe
仍然拥有属于自己的滚动条。
iframe的优缺点
优点
- 作为一个完全独立的窗口去运行另一个页面,而不用去担心污染。
- 解决加载缓慢的第三方内容如图标和广告等的加载问题
- 并行的加载资源文件
缺点
- 占用同源连接数,对于每个浏览器,都会去控制并发的同源的连接数。比如说chrome的连接数是8,firfox的连接数6。所以如果iframe的请求与页面的请求是同源的,那么就会阻塞页面的请求。
- iframe无法使用浏览器的前进和后退键
- 对SEO不友好
- 阻塞onload的加载
iframe的简单使用
<iframe id="inlineFrameExample"
width="300"
height="200"
src="https://www.openstreetmap.org/export/embed.html?bbox=-0.004017949104309083%2C51.47612752641776%2C0.00030577182769775396%2C51.478569861898606&layer=mapnik">
</iframe>
你可能不知道用途
不使用websocket
进行轮询
在websocket
无法使用的时候,作为长轮询功能的解决方案。主要用于实现ie8、9这种早期浏览器的轮询功能。一开始在谷歌中有使用过Comet:基于 HTTP 长连接的“服务器推”技术
1. 创建服务端,新建一个接口
/* GET users listing. */
router.get('/users', function(req, res, next) {
res.send('respond with a resource');
});
2. 编写客户端js
<div class="iframe-content" />
<script>
// 创建一个iframe并将它隐藏
const iframeEle = document.createElement('iframe');
iframeEle.style = 'display: none;';
iframeEle.name = 'poll';
iframeEle.src="http://localhost:3000/users";
// 监听load事件,请求完成后将会运行load事件
iframeEle.onload = function() {
var iframeLoc = iframeEle.contentWindow.location;
var result = iframeEle.contentDocument;
// 这里将会拿到响应的结果
var text = result.getElementsByTagName('body')[0].textContent;
console.log(text)
// 设置定时器,实现轮询功能
setTimeout(function() {
iframeLoc.reload();
}, 3000);
}
var iframeContent = document.getElementsByClassName('iframe-content')[0];
iframeContent.appendChild(iframeEle);
</script>
不使用formData上传文件
当我们不能使用formData
上传文件时,我们可以使用iframe
进行页面无刷新的上传文件。方法其实很简单,就是使用iframe
代替当前页面上传,只需要将定义好的form
标签的target
赋值为iframe
的name
属性。
- 页面代码
<form id="submit-form" name="submit-form" target="submit-iframe" enctype="multipart/form-data" action="/upload" method="POST">
<input type="file" name="files">
<button type="submit" id="submit-btn">上传</button>
</form>
需要注意到。iframe的name和form的target属性是一致的
<iframe style="display: none;" id="submit-iframe" name="submit-iframe"></iframe>
<script>
const iframeEle = document.getElementById('submit-iframe');
// 上传完成后,可以在iframe中拿到响应的结果
iframeEle.onload= function() {
var iframeLoc = iframeEle.contentWindow.location;
var resultWrapper = iframeEle.contentDocument;
var result = resultWrapper.getElementsByTagName('body')[0].textContent;
console.log(result);
}
</script>
- 上传接口
var express = require('express');
var multer = require('multer');
var router = express.Router();
let storage=multer.diskStorage({
destination:(req,file,cb)=>{
cb(null,'upload/');
},
filename:(req,file,cb)=>{
cb(null,file.originalname);
}
})
var upload = multer({
storage
})
router.post('/upload', upload.single('files'),function(req, res, next) {
res.send("上传完成");
})
iframe跨域解决跨域请求
1. 创建主页面
主页面中包含了2个iframe
,一个用于请求不同域的接口fetchFrame
。一个用于轮询监听前者的location
变化observeFrame
。且主页面包含一个回调方法用于供observeFrame
调用。
<div class="iframe-content">
<div>主页面</div>
<!-- 同域 -->
<iframe src="http://hsa.guahao-test.com:3000/fetch.html" name="fetch" id="fetch"></iframe>
<!-- 不同域 -->
<iframe src="http://tcmedev.udplat.com:8080/observe.html" name="inner" id="inner"></iframe>
</div>
<script>
// 主页面用于iframe的回调函数
window.message = function(str) {
console.log(str);
}
</script>
2. 编写fetchFrame的代码
在fetchFrame
的页面中,可以看到代码使用setTimeout
进行模拟异步请求,在回调函数中会将结果存放进window.name
中,并改变location
的指向。需要注意的是,我们使用的是window.name
去处理iframe
的数据传递。因为window.name
在改变窗口地址的情况下不会改变数据且它具有2M的空间大小。但是在不同域的情况下,window.name
无法被访问到,所以在赋值完成后会改变iframe
的地址。
setTimeout(() => {
// 存放数据
window.name = new Date();
// 改成location,使得与主页面同源
window.location = 'http://tcmedev.udplat.com:8080/index3.html'
}, 3000);
3. 编写observeFrame的代码
在observeFrame
中,创建了一个定时器去轮询fetchFrame
的window
对象,在不同域的情况下,访问异步的iframe
会抛出错误。所以代码中使用try-catch
进行包裹,当fetchFrame
将location
改为同域的时候,就可以正常的访问fetchFrame
的window.name
,并调用父级的回调函数。
<script>
var fetchFrame = window.parent.document.getElementById('fetch');
if(fetchFrame) {
const interval = setInterval(() => {
const fetchFrameWindow = fetchFrame.contentWindow;
const hostname = fetchFrameWindow.location;
try {
// 这时,请求已经完成
if(fetchFrameWindow.location.hostname !== hostname) {
clearInterval(interval);
if(window.top && window.top.message) {
// 调用主页面声明的回调函数
window.top.message(fetchFrameWindow.name)
}
}
} catch (error) {
// 捕获跨域异常
console.log("还在请求当中")
}
}, 1000);
}
</script>
浏览器端实现utf8和gbk编码互转
在开发的过程中,有时难免会遇到编码问题。比如说服务端需要提交的参数是gbk,又或者我们需要使用到gbk的字符串。对于这些场景,使用JavaScript的encodeURI
或者encodeURIComponent
等浏览器的全局api都无法完成。但可以使用form标签的accept-charset
,以下为文档上的描述
举一个简单的例子
<form action="form_action.asp" accept-charset="gbk">
<input type="text" name="test" value="这里是一串字符串" />
<input type="submit" value="Submit" />
</form>
尝试提交后,得到的结果是
我们可以看到请求的query上test后面跟着一串(unable to decode value)
, 这是因为gbk编码无法解析。
我们已经有了生成gbk编码的字符串的方法了。但是还是没法拿到。这个时候就可以用前面使用到的form标签的target。
使用target=“framename”就可以提交字符串到对应的iframe,而在iframe中我们就能拿到编码完成的字符串了。
<form target="encode" accept-charset="gbk" >
<input type="text" name="test" value="这里是一串字符串" />
<input type="submit" value="Submit" />
</form>
<iframe name="encode" style="display:none" src='about:blank' id="encode"></iframe>
<script>
// 上面代码中创建了一个iframe标签和form标签,form标签会把表单提交到encode的iframe
var frame = document.getElementById("encode");
// 定义了一个回调函数
window.callback = function(result) {
console.log(result);
}
// 从iframe的onload事件得到结果
frame.onload = function() {
//打印frame的location.search可以得到 ?test=%D5%E2%C0%EF%CA%C7%D2%BB%B4%AE%D7%D6%B7%FB%B4%AE
result = frame.contentWindow.location.search.split("=")[1]
frame.contentWindow.parent.callback(result)
}
</script>
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!