分类 默认分类 下的文章
iframe 高度自适应功能
内容转自:https://liaoxuefeng.com/blogs/all/2024-02-25-auto-resize-iframe/index.html
使用iframe嵌入页面很方便,但必须在父页面指定iframe的高度。如果iframe页面内容的高度超过了指定高度,会出现滚动条,很难看。
如何让iframe自适应自身高度,让整个页面看起来像一个整体?
在HTML5之前,有很多使用JavaScript的Hack技巧,代码量大,而且很难通用。随着现代浏览器引入了新的ResizeObserver API[1],解决iframe高度问题就变得简单了。
我们假设父页面是index.html,要嵌入到iframe的子页面是target.html,在父页面中,先向页面添加一个iframe:
const iframe1 = document.createElement('iframe');
iframe1.src = 'target.html';
iframe1.onload = autoResize;
document.getElementById('sameDomain').appendChild(iframe1);当iframe载入完成后,触发onload事件,然后自动调用autoResize()函数:
function autoResize(event) {
// 获取iframe元素:
const iframeEle = event.target;
// 创建一个ResizeObserver:
const resizeRo = new ResizeObserver((entries) => {
let entry = entries[0];
let height = entry.contentRect.height;
iframeEle.style.height = height + 'px';
});
// 开始监控iframe的body元素:
resizeRo.observe(iframeEle.contentWindow.document.body);
}通过创建ResizeObserver,我们就可以在iframe的body元素大小更改时获得回调,在回调函数中对iframe设置一个新的高度,就完成了iframe的自适应高度。
跨域问题
ResizeObserver很好地解决了iframe的监控,但是,当我们引入跨域的iframe时,上述代码就失效了,原因是浏览器阻止了跨域获取iframe的body元素。
要解决跨域的iframe自适应高度问题,我们需要使用postMessage机制,让iframe页面向父页面主动报告自身高度。
假定父页面仍然是index.html,要嵌入到iframe的子页面是http://xyz/cross.html,在父页面中,先向页面添加一个跨域的iframe:
const iframe2 = document.createElement('iframe');
iframe2.src = 'http://xyz/cross.html';
iframe2.onload = autoResize;
document.getElementById('crossDomain').appendChild(iframe2);在cross.html页面中,如何获取自身高度?
我们需要现代浏览器引入的一个新的MutationObserver API[2],它允许监控任意DOM树的修改。
在cross.html页面中,使用以下代码监控body元素的修改(包括子元素):
// 创建MutationObserver:
const domMo = new MutationObserver(() => {
// 获取body的高度:
let currentHeight = body.scrollHeight;
// 向父页面发消息:
parent.postMessage({
type: 'resize',
height: currentHeight
}, '*');
});
// 开始监控body元素的修改:
domMo.observe(body, {
attributes: true,
childList: true,
subtree: true
});当iframe页面的body有变化时,回调函数通过postMessage向父页面发送消息,消息内容是自定义的。在父页面中,我们给window添加一个message事件监听器,即可收取来自iframe页面的消息,然后自动更新iframe高度:
window.addEventListener('message', function (event) {
let eventData = event.data;
if (eventData && eventData.type === 'resize') {
iframeEle.style.height = eventData.height + 'px';
}
}, false);使用现代浏览器提供的ResizeObserver和MutationObserver API,我们就能轻松实现iframe的自适应高度。
文档:
ResizeObserver接口监视Element或者SVGElement尺寸的变化。 ↩︎
https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver#%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7
MutationObserver接口提供了对DOM树更改的监视能力。 ↩︎
https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver#%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7
gitsite 从 Git 中的 Markdown 文档快速构建现代网站
GitSite 可以将组织良好的 Markdown 文档和其他资源构建到静态网站,部署到 GitHub 页面等。
Markdown 文档
gitsite-cli 工具
建
部署
静态网站
GitHub 页面
GitLab 页面
CloudFlare页面
S3 网站托管
韦尔塞尔
自托管 Nginx
例:
GitHub 存储库: https://github.com/michaelliao/gitsite 可以部署到:
GitHub:https://gitsite.org
GitLab:https://gitlab.gitsite.org
Cloudflare:https://cloudflare.gitsite.org
Vercel: https://vercel.gitsite.org
GitSite 支持 Markdown 文档、嵌入式视频、数学表达式、ASCII 艺术、二维码、图表,甚至乐谱!
JS复制图片功能 canvas.toBlob img clipboard
$(".btn-copy-qrcode-image").click(function(e) {
//复制图片功能
var img = $('#' + $(this).data('target'))[0] //tag: img
var canvas = document.createElement('canvas')
canvas.width = img.naturalWidth
canvas.height = img.naturalHeight
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0)
canvas.toBlob(async blob => {
const data = [
new ClipboardItem({
[blob.type]: blob,
}),
];
await navigator.clipboard.write(data)
.then(
() => {
simpleDialog({
msg: '复制成功'
})
},
() => {
simpleDialog({
msg: '复制失败,请右键选择【复制图像】'
})
}
);
});
})toBlob报错
图片跨域问题,img元素加上这个属性 crossorigin="anonymous"
Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported... 点击任意元素/通过JS不使用input控件也能触发文件选择功能
文章转自张鑫旭博客,原文地址:https://www.zhangxinxu.com/wordpress/2021/08/file-system-access-api/
一、温故而知新
传统在Web端文件上传,都是使用file类型的表单input框:
<input type="file">file input框
我们可以通过accept属性指定选择的文件类型,directory属性指定是否可以选择文件夹,capture属性指定前置或后置摄像头。
功能还是很强的。
具体可以见我之前这篇文章:“HTML input type=file文件选择二三事”
但是file输入框有个致命的缺点,就是 UI 太丑了,并且无法定制。
虽然使用
那有没有什么办法点击一个普通的按钮,也能触发文件选择呢?最好可以设置选择文件夹还是文件,设置选择的文件格式类型。
还真有,现代Web不断发展,出现了一个新的API,叫做 File System Access API,可以实现点击任意元素触发文件选择。
二、showOpenFilePicker方法
假设页面上有个按钮,其HTML如下所示:
则下面几行JavaScript代码就可以实现点击按钮出现文件选择:
button.addEventListener('click', function () {
// 打开文件
window.showOpenFilePicker();
});真是简单又粗暴,直接又了当。
当然,我们也可以使用 showDirectoryPicker() 方法来选择文件夹。
button.addEventListener('click', function () {
// 打开文件夹
window.showDirectoryPicker();
});由于两个API参数和作用类似,因此里只详细介绍文件的选择。
文件类型、多选与否的指定
showOpenFilePicker(options) 方法中是可以传参的,具体支持的参数如下:
其中,options是可选参数,支持下面这些属性:
multiple
布尔值,默认值是 false ,表示只能选择一个文件。
excludeAcceptAllOption
布尔值,默认值是 false ,表示是否排除下面 types 中的所有的accept文件类型。
types
可选择的文件类型数组,每个数组项也是个对象,支持下面两个参数:
description:表示文件或者文件夹的描述,字符串,可选。
accept:接受的文件类型,对象,然后对象的键是文件的MIME匹配,值是数组,表示支持的文件后缀。具体可以下面的示意。
例如下面的JS代码执行就是可以一次性选择多张本地桌面图片:
window.showOpenFilePicker({
types: [{
description: 'Images',
accept: {
'image/*': ['.png', '.gif', '.jpeg', '.jpg', '.webp']
}
}],
// 可以选择多个图片
multiple: true
});三、演示-点击按钮选择并显示多图
上面知道了选择文件,但是如何处理选择后的文件呢,下面有个例子,对大家学习会很有帮助。
完整代码如下:
<button id="button">选择图片</button>
<p id="output"></p>
button.addEventListener('click', async function () {
// 打开文件
const arrFileHandle = await window.showOpenFilePicker({
types: [{
accept: {
'image/*': ['.png', '.gif', '.jpeg', '.jpg', '.webp']
}
}],
// 可以选择多个图片
multiple: true
});
// 遍历选择的文件
for (const fileHandle of arrFileHandle) {
// 获取文件内容
const fileData = await fileHandle.getFile();
// 读文件数据
const buffer = await fileData.arrayBuffer();
// 转成Blod url地址
let src = URL.createObjectURL(new Blob([buffer]));
// 在页面中显示
output.insertAdjacentHTML('beforeend', `<img src="${src}">`);
}
});这个例子有对应的demo,您可以狠狠地点击这里:文件访问API 触发图片选择demo
点击demo页面这个蓝色按钮:
点击蓝色按钮
选择自己电脑中对应的图片,例如我选择了2张不错的PNG图片:
选择图像截图示意
结果在Web页面上成功预览了图片效果,如下截图所示:
页面上预览效果示意
是不是跟传统的file文件选择很类似。
由于这些全新的API都是走的Promise,因此,可以使用async、 await等新的JS语法,避免各种乱糟糟的回调,代码更简洁更易读了。
是不是很赞!
四、可惜是个新API
对于不喜欢HTML表单元素,喜欢JavaScript代码一把梭的开发者而言,这个API会很亲近很喜欢,但是,遗憾的是,这个API出来的比较新,去年下半年才出来,Safari浏览器并不支持,因此,不能直接使用。
兼容性
不过,有不少项目做了mix混合处理,也就是写了个 JS,支持的浏览器使用 File System Access API,不支持的浏览器还是使用传统的 ,例如谷歌实验室的这个项目 browser-fs-access
如果是文件保存或下载,则可以试试window.showSaveFilePicker()这个 API,有时候可以介绍下,当然,实际开发,文件下载肯定是使用 FileSaver.js,这可以文件下载当仁不让的王者,标杆项目。
其他限制
需要https环境,如果是本地localhost 不受此限制。
不能在 iframe 内使用,因为被认为不安全