最近在做一个系统导出图片,然后到大屏上进行展示的功能。因为之前做了很多的excel模板导出、word模板导出,所以首先想到的是在网上找java实现模板导出的方案,百度之后发现一个貌似可行的方案:导出word->word转pdf->pdf转为png。这。。。好像有着亿丝丝的复杂,那么怎么简单的完成这个需求呢?
如果将需要导出的图片模板先用网页写出来,再把数据渲染上,最后将网页的部分区域截取为一张图片。
1. 核心知识点
html2canvas,将网页区域转为canvas。canvas.toDataURL(),使用canvas的api转换为base64。- 使用a标签将base64下载为具体的图片文件。
2. 效果展示
网页截图
图片截图
3. 具体步骤
1. 构建DOM模板
项目框架是使用的Vue,构建这么一个DOM模板还是很简单的。上代码
<div style="margin-top: 10px">
<a-empty v-if="!recipeData.list.length" />
<div class="export-area" v-else>
<!-- 图片区域-->
<div class="left"></div>
<!-- 数据区域-->
<div class="main">
<div class="title">
<div class="time-interval">{{ recipeData.timeInterval_dictText }}</div>
<div class="day">{{ recipeData.recipeDate_dictText }}</div>
</div>
<!-- 不同类型的数据单独渲染-->
<a-row class="recipe-area" v-for="key of ['other','3','6']" :key="key">
<a-col :span="12" v-for="item of recipeMap[key]" :key="item.id">
<div class="recipe-name">{{ item.dishName }}</div>
</a-col>
</a-row>
</div>
</div>
</div>
2. 装载数据
发起Get请求获取到数据,然后对数据进行一系列的处理(例如今天周几等等),代码太长,就不贴上来了。
3. 导出图片
利用上面说到的相关知识点,完成图片的导出。代码如下
handleExportImage() {
if (this.recipeData.list.length > 0) {
html2canvas(document.querySelector(".export-area")).then((canvas) => {
//利用a标签的download属性,直接下载,避免上传服务器再下载
let link = document.createElement("a");
link.style.display = "none";
link.href = canvas.toDataURL();
link.setAttribute("download", `${this.model.recipeDate}_${this.recipeData.recipeDate_dictText}_${this.recipeData.timeInterval_dictText}图片`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link); //下载完成移除元素
});
} else {
this.$message.warn("暂无数据!");
}
},
总结
因为之前做了很多的word、excel导入导出的影响、一看到导出的功能,思维就固化成后端使用模板导出来做了,结果前端做会更简单(后端我也没做,原谅我的妄言)。