前言
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
大家好,我是前端小张同学,接着上一次的demo所遇到的问题就是,项目需要根据一张大的流程图,生成一个小的缩略图,当时我........,这是什么需求,做不了,于是我经过自己的努力还是做出来了中间也遇到了很多问题,在这里跟大家分享一下,如果你觉得有用请点个 Star
。
需求:
项目希望根据大的流程图绘制小的缩略图,具体内容我们看下方大图。
大图
缩略图
思考,这应该怎么做......
刚拿到这个需求的时候我楞了一下,应该怎么做?我的第一想法 居然是.....Alt + A
(微信截图快捷键
)
,我手动截一张图,然后保存,再然后...... 很明显这不现实,但是我们思路没错,截图
,对,你没听过就是截图,我完成了这个需求。
接下来 (心机之蛙一直摸你肚子)
我利用了一个库截取了Dom的节点内容。
介绍一下这个库
什么是 html2canvs?
来源 : github ----> html2canvas
html2canvas
的作用就是允许让我们直接在用户浏览器上拍摄网页或其部分的“截图”。
它的屏幕截图是基于 DOM
的,因此可能不会 100% 精确到真实的表示,因为它不会生成实际的屏幕截图,而是基于页面上可用的信息构建屏幕截图。
html2canvas 可以用来做什么?
从上的面的介绍可以知道, html2canvas
的作用就是根据 DOM
生成对应的图片,所以一个比较常见的应用场景就是我们可以使用它在 H5
端生成分享图,或者生成缩略图等。
如何使用 html2canvas呢?
三部曲
下包
---> 引入
----> 使用
1:下包
npm i html2canvas
或
yarn add html2canvas
2:引入
import html2canvas from 'html2canvas'
3:使用(use)
在Vue中我们可以通过 给DOM绑定 ref
来获取到当前DOM节点。如果你是原生JS,
请document.querySelector()
配置项请见 html2canvas官方文档:
html2canvas.hertzen.com/configurati…
// 获取DOM实例对象 你获取哪个DOM节点,截图的区域就是哪个元素的内容
const el = this.$refs.efContainer;
// 获取元素的宽
const width = el.offsetWidth
//获取元素的高
const height = el.offsetHeight
// html2canvas- 我这里接收 两个参数
// 参数1 : 传递需要截图的DOM元素
// 参数2 : 需要的配置对象,可以配置截图的宽高,跨域,缩放比例等等
// 具体可见 :http://html2canvas.hertzen.com/configuration
let canvas = html2canvas(el,{
// 意思就是 如果你的资源是从服务器来的,可以尝试在服务端加载图像,我们设置为true
useCORS:true, //官方:是否尝试使用CORS从服务器加载图像
scale: 2, // 图像的缩放比例
// 如果不知道简写是什么意思 请看 # 阮一峰js教程
width, // 图像的宽度,因为我这里属性名和属性值一致可以简写
height, // 来自于 const height = el.offsetHeight
allowTaint:true, // allowTaint 允许绘制画布
windowHeight:height,// 渲染Element时使用的窗口宽度
// backgroundColor: "#fff"那你还可以设置颜色
// 这样你已经完成了一个截图了
})
接下来,你可以通过 canvas.toDataURL('images/jpg')
获取到一张base64位的图片进行展示
//toDataURL(生成图片格式)
const img = canvas.toDataURL('images/jpg')
问题
如果你出现了白屏
,请考虑你的方法调用时机
,确保DOM真正绘制完后在进行截取操作,你可以在点击某个按钮去执行该方法。例如 像我这样
如果有滚动条的DOM截图出现白屏
请参考
www.51sjk.com/b24b265777/
解决 无法截取Svg
相信根据上方的操作你应该可以生成一个base64
的字符串了 放到 image src 属性身上可以进行展示了。
接下来 ,很明显看的出,我想截取这个 id
为 efContainer
DOM元素里的内容,很明显可以看的出该元素的子节点是有svg
标签的。
原图
截取之后的
我们使用 html2canvas
截取一个DOM内容是无法截取到SVG的内容的,这也是一个缺陷吧。如何解决呢
?
解决方案
解决思路
也是来自于github issues 里的大佬 github.com/niklasvh/ht…);
采取的是将Svg
标签提取出来,绘制成进canvas
行截取 展示的,同时相当于是 障眼法 ,我用 canvas
去代替你的 SVG
这样就可以正常的截取了
怎么做呢?
你需要先 下载一个包
三部曲
下包
---> 引入
----> 使用
npm install canvg@1.5.3
import canvg from 'canvg'
思路:
1:准备一个获取Svg DOM元素的数组;
2:获取SVG DOM元素;
3: 循环遍历Svg DOM 数组,并且解决SVG 透明度问题;
4:去除元素的一个空白字符;
5:动态创建一个 canvas
标签;
6: 设置 创建好的 canvas
标签的宽高;
7:canvg() 使用这个方法 将 SVG
转换成 canvas
;
8:设置 canvas
的坐标;
9:添加到你想截图的DOM元素中;
10:截取完成后 将将绘制好的 canvas
删除避免影响后续操作
async getContainerImg () {
const el = this.$refs.efContainer;
//Svgdom数组
let svgNodesToRemove = [];
// 获取到所有的SVG 得到一个数组
let svgElements = document.body.querySelectorAll('#efContainer svg');
// 遍历这个数组
svgElements.forEach(function(item) {
let children = item.childNodes
// 处理 SVG子节点 children 透明度
children.forEach(function(child) {
//解决svg透明度问题
child.style.opacity = 1;
})
//去除空白字符
let svg = item.outerHTML.trim();
// 创建一个 canvas DOM元素
let canvas = document.createElement('canvas');
//设置 canvas 元素的宽高
canvas.width = item.getBoundingClientRect().width;
canvas.height = item.getBoundingClientRect().height;
// 将 SVG转化 成 canvas
canvg(canvas, svg);
//设置生成 canvas 元素的坐标 保证与原SVG坐标保持一致
if (item.style.position) {
canvas.style.position += item.style.position;
canvas.style.left += item.style.left;
canvas.style.top += item.style.top;
}
//添加到 你需要截图的DOM节点中
item.parentNode.appendChild(canvas);
// 删除这个元素
svgNodesToRemove.push(canvas)
});
const width = el.offsetWidth
const height = el.offsetHeight
let canvas = await html2canvas(el,{
useCORS:true,
scale: 2,
width,
height,
allowTaint:true,
// dpi: window.devicePixelRatio * 4,//设备像素比
// windowWidth:document.body.scrollWidth,
windowHeight:height,
// x:0,
// y:window.pageYOffset
// backgroundColor: ""
})
this.thumbnail = canvas.toDataURL('images/jpg')
// 截取完成后
// 删除 canvas 元素
document.querySelectorAll("#efContainer canvas").forEach(item => {
item.remove()
})
},
那缩略图的话,相信你通过CSS就可以搞定它了。大概内容就是这样咯。
这样就可以完美解决 无法截取到SVG的问题啦,非常谢谢大家的支持,如果你觉的本文对你有帮助请点个👍,谢谢,如果有更好的思路,请在文章下方留言,谢谢。