重点:因为 dom-to-image.js 是根据 元素转换svg 进行截图的,所以如果元素有滚动条,他只能截图到 滚动条的顶部,不能截图到对应的滚动条位置
dom-to-image.js 引入
1、下载
yarn add dom-to-image
2、在 node_modules 文件夹中 找到 dom-to-image 文件夹里面的 dom-to-image.js 复制出来
3、 页面引入
import domtoimage from 'dom-to-image.js';
dom-to-image.js 修改
不修改也可以,我这边是因为使用了 阿里的oss,不能在后面加时间戳,所以修改
// 找到 文件中的 getAndEncode 方法,修改里面的 url
url += ((/\?/).test(url) ? "&" : "?")
dom-to-image.js 提供的方法
1、domtoimage.toPng(…);将节点转化为png格式的图片
2、domtoimage.toJpeg(…);将节点转化为jpg格式的图片
3、domtoimage.toSvg(…);将节点转化为svg格式的图片,生成的图片的格式都是base64格式
4、domtoimage.toBlob(…);将节点转化为二进制格式,这个可以直接将图片下载
5、domtoimage.toPixelData(…);获取原始像素值,以Uint8Array 数组的形式返回,每4个数组元素表示一个像素点,即rgba值。这个方法也是挺实用的,可以用于WebGL中编写着色器颜色。
dom-to-image.js 方法中接受的参数
所有参数都可以不写,有默认的;
注意的是 `cacheBust` 参数,用于判断图片是否跨域
参数 | 说明 | 类型 |
filter | 过滤器节点中默写不需要的节点; | function |
bgcolor | 图片背景颜色; | string |
height, width | 图片宽高; | string |
style | 传入节点的样式,可以是任何有效的样式; | object |
quality | 图片的质量,也就是清晰度;一个介于 0 和 1 之间的数字,表示 JPEG 图像的图像质量(例如 0.92 => 92%)。默认为 1.0 (100%) | number |
cacheBust | 将时间戳加入到图片的url中,相当于添加新的图片; | Boolean |
imagePlaceholder | 图片生成失败时,在图片上面的提示,相当于img标签的alt; | string |
dom-to-image.js 方法使用
domtoimage.toPng(需要截图的元素,{ cacheBust: true }).then(function (dataUrl) {
//console.log(dataUrl)
})
.catch(function (error) {
console.error('生成失败', error);
});
dom-to-image.js bug修复
1、截图返回的图片,截不全
- 发现页面截不全, toPng 截不全的 可替换 toBlob 进行截图
domtoimage.toPng(toBlob,{
filter: (el) => {
// 过滤 VIDEO 标签
return !(el.tagName === 'VIDEO')
},
}).then(function (toBlob) {
console.log(toBlob)
})
2、视频画面截图不到
- 先把视频当前画面转成 canvas
- 使用 canvasBox.getElementsByTagName('video') 获取的数组 不能使用 forEach 修改成 for
// 1 、先把视频当前画面转成 canvas
const canvasBox = this.$refs.截图元素
/* 视频 (新增一个canvas 标签到同级) */
const canvasList = []
const videoElList = []
/* 找到元素下的所有 video 标签*/
const videoList = canvasBox.getElementsByTagName('video')
for (let i = 0; i < videoList.length; i++) {
const el = videoList[i]
if (el.tagName === 'VIDEO') {
var canvas = document.createElement('canvas')
var videoRatio = el.videoWidth / el.videoHeight;
var width = el.offsetWidth, height = el.offsetHeight;
var elementRatio = width / height;
if(elementRatio > videoRatio) {
width = height * videoRatio;
} else {
height = width / videoRatio;
}
canvas.width = width
canvas.height = height
canvas.className = 'juzhong'
canvas.style.cssText = el.style.cssText
const ctx = canvas.getContext('2d')
ctx.drawImage(el, 0, 0, width, height)
if (el.parentNode && el.parentNode.appendChild) {
el.parentNode.appendChild(canvas)
}
canvasList.push(canvas)
}
}
// 2、开始截图,过滤视频标签
domtoimage.toPng(canvasBox,{
filter: (el) => {
// 过滤 VIDEO 标签
return !(el.tagName === 'VIDEO')
},
}).then(function (dataUrl) {
/* 视频 (删除 替换的 canvas 标签) */
canvasList.forEach(el => {
el.parentNode.removeChild(el)
})
})
3、svg 使用了 svg-sprite-loader,导致截图内容不展示 svg
- 按照下方代码执行
- 使用 canvasBox.getElementsByTagName('video') 获取的数组 不能使用 forEach 修改成 for
// 1、在 svgIcon.vue 组件中,新增一个 svgName
<svg :class="svgClass" aria-hidden="true" :svgName="svgName">
<use :xlink:href="iconName" />
</svg>
// 2、在截图元素中的 svg 插入内容
const canvasBox = this.$refs.截图元素
/* svg (找到 symbol 并移动到 svg 标签中) */
const symbolList = []
const svgList = canvasBox.getElementsByTagName('svg')
for (let i = 0; i < svgList.length; i++) {
const el = svgList[i]
if (el.id === '__SVG_SPRITE_NODE__') {
return
}
const svgName = el.getAttribute('svgName')
const item = document.getElementById(`icon-${svgName}`)
symbolList.push(item)
el.appendChild(item)
}
// 3、开始截图
domtoimage.toPng(canvasBox).then(function (dataUrl) {
/* svg (把获取的 symbol 移回去) */
const svgPublic = document.getElementById('__SVG_SPRITE_NODE__')
symbolList.forEach(el => {
svgPublic.appendChild(el)
})
})
4、阿里的oss 图片加载失败
- 在复制出来的 dom-to-image.js 文件 搜索 getAndEncode 函数
// 找到 文件中的 getAndEncode 方法,修改里面的 url
url += ((/\?/).test(url) ? "&" : "?")
5、图片链接失效,访问不了,导致失败
- 在复制出来的 dom-to-image.js 文件 搜索 newImage 函数
- 找到 newImage 函数 里面的 inline 函数 的下方代码
// 原本代码
return new Promise(function (resolve, reject) {
element.onload = resolve;
element.onerror = reject
element.src = dataUrl;
});
// 修改后
return new Promise(function (resolve, reject) {
element.onload = resolve;
element.onerror = (e) => {
// 不管怎么样都执行 resolve
resolve()
};
element.src = dataUrl;
});
6、合成图片模糊
- 在复制出来的 dom-to-image.js 文件 搜索 newCanvas 函数
// 原本代码
function newCanvas(domNode) {
var canvas = document.createElement('canvas');
canvas.width = options.width || util.width(domNode);
canvas.height = options.height || util.height(domNode);
if (options.bgcolor) {
var ctx = canvas.getContext('2d');
ctx.fillStyle = options.bgcolor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
return canvas;
}
// 修改后
function newCanvas(domNode) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
var scale = options.scale || 1; // 默认值1
canvas.width = (options.width * scale) || util.width(domNode);
canvas.height = (options.height * scale) || util.height(domNode);
ctx.scale(scale, scale) // 添加了scale参数
if (options.bgcolor) {
ctx.fillStyle = options.bgcolor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
return canvas;
}
// 使用 toBlob 作为例子
domtoimage.toBlob(canvasBox, {
width: 80,
height:80,
scale: 8
})