在工作中偶尔会遇到要将整个网页或者网页的局部转为图片保存下来,最开始使用html2canvas,发现只能转可视窗口里面的元素,并且会存在css样式乱码、饿了么组件变形等问题,最后发现使用dom-to-image可以实现自己的需求
一、安装dom-to-image
npm install dom-to-image
二、演示页面
先做一个简单的demo页面,做了预览功能和下载功能。
<template>
<div class="content">
<div class="left">
<el-button type="primary" @click="preview">预览</el-button>
<el-button type="primary" @click="download">下载</el-button>
<el-image
style="width: 200px; height: auto;margin-top: 100px"
:src="imgUrl"
:zoom-rate="1.2"
:max-scale="7"
:min-scale="0.2"
:preview-src-list="[imgUrl]"
:initial-index="1"
fit="cover"
/>
</div>
<div class="right" ref="rightRef">
<div class="item red"></div>
<div class="item green"></div>
<div class="item blue"></div>
<div class="item gray"></div>
</div>
</div>
</template>
<style scoped lang="scss">
.content {
width: 100vw;
height: 100vh;
display: flex;
.left {
width: 300px;
}
.right {
flex: 1;
overflow: auto;
}
.item {
width: 100%;
height: 33%;
margin-bottom: 20px;
}
.red {
background-color: rgba(255, 0, 0, .5);
}
.green {
background-color: rgba(0, 255, 28, .5);
}
.blue {
background-color: rgba(55, 2, 255, .5);
}
.gray {
background-color: rgba(179, 179, 179, .5);
}
}
</style>
三、dom-to-image的使用
import domtoimage from 'dom-to-image';
const rightRef = ref() //要进行转化为图片的元素对象
const imgUrl = ref() //用于存储图片地址
//预览图片
function preview() {
domtoimage.toPng(rightRef.value)
.then(function (base64Image:any) {
imgUrl.value = base64Image //转化出来后的数据是base64的类型
})
}
点击预览后,当前窗口中的元素就已经被转为图片格式了
四、当前页面超出滚动条部分的处理
根据dom-to-image官网:https://github.com/tsayen/dom-to-image?tab=readme-ov-file的提示,可以设置图片的宽高和样式
于是可以在生成图片的时候,将图片的宽高设置为所需元素的宽高
//预览图片
function preview() {
// 临时移除高度限制(如果需要)
const originalHeight = rightRef.value.style.height;
rightRef.value.style.height = 'auto'; //先把高度放开
// 定义图片的变量
const option = {
width: rightRef.value.scrollWidth, // 确保宽度包含所有内容
height: rightRef.value.scrollHeight, // 确保高度包含所有内容
style: {
overflow: 'visible', // 确保内容不会被裁剪
},
}
domtoimage.toPng(rightRef.value,option)
.then(function (base64Image:any) {
rightRef.value.style.height = originalHeight; // 再将盒子恢复成原样
imgUrl.value = base64Image
})
}
这个时候,点击预览出现的图片,就会是完整的元素图片
再添加一个下载功能
function download() {
// 下载日报图片
const a = document.createElement('a');
a.href = imgUrl.value;
a.download = '网址转图片.png';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
五、完整demo代码
<script setup lang="ts">
import {ref} from 'vue'
import domtoimage from 'dom-to-image';
const rightRef = ref() //需要进行网页转图片的实例
const imgUrl = ref() //用于存放base64
//预览图片
function preview() {
// 临时移除高度限制(如果需要)
const originalHeight = rightRef.value.style.height;
rightRef.value.style.height = 'auto'; //先把高度放开
// 定义图片的变量
const option = {
width: rightRef.value.scrollWidth, // 确保宽度包含所有内容
height: rightRef.value.scrollHeight, // 确保高度包含所有内容
style: {
overflow: 'visible', // 确保内容不会被裁剪
},
}
domtoimage.toPng(rightRef.value,option)
.then(function (base64Image:any) {
rightRef.value.style.height = originalHeight; // 再将盒子恢复成原样
imgUrl.value = base64Image
})
}
function download() {
// 下载日报图片
const a = document.createElement('a');
a.href = imgUrl.value;
a.download = '网址转图片.png';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
</script>
<template>
<div class="content">
<div class="left">
<el-button type="primary" @click="preview">预览</el-button>
<el-button type="primary" @click="download">下载</el-button>
<el-image
style="width: 200px; height: auto;margin-top: 100px"
:src="imgUrl"
:zoom-rate="1.2"
:max-scale="7"
:min-scale="0.2"
:preview-src-list="[imgUrl]"
:initial-index="1"
fit="cover"
/>
</div>
<div class="right" ref="rightRef">
<div class="item red"></div>
<div class="item green"></div>
<div class="item blue"></div>
<div class="item gray"></div>
</div>
</div>
</template>
<style scoped lang="scss">
.content {
width: 100vw;
height: 100vh;
display: flex;
.left {
width: 300px;
}
.right {
flex: 1;
overflow: auto;
}
.item {
width: 100%;
height: 33%;
margin-bottom: 20px;
}
.red {
background-color: rgba(255, 0, 0, .5);
}
.green {
background-color: rgba(0, 255, 28, .5);
}
.blue {
background-color: rgba(55, 2, 255, .5);
}
.gray {
background-color: rgba(179, 179, 179, .5);
}
}
</style>