需求
html2canvas生成圖片翰苫,不會(huì)隨著屏幕窗口rize大小變化而變化,但頁面上是正常顯示 谨履。無論移動(dòng)端或pc端都生成固定寬度(1300px)欢摄,且生成內(nèi)容完全展示,這個(gè)寬度根據(jù)自己的需求變化笋粟。
實(shí)現(xiàn)思路
- 父頁面寫兩個(gè)一樣的兄弟組件OriginalBoard和FinalBoard2
- OriginalBoard組件默認(rèn)正常顯示
- FinalBoard2組件隱藏(使用z-index)
- OriginalBoard組件觸發(fā)點(diǎn)擊按鈕怀挠,把值傳給父組件index,再通過index傳給FinalBoard2
- 兩個(gè)兄弟組件的樣式共用一份害捕,如對(duì)生成圖片的頁面顯示有要求的話绿淋,可以再單獨(dú)修改。
用html2canvas生成圖片需要特別注意以上幾點(diǎn):
生成圖片是基于dom節(jié)點(diǎn)來生成的尝盼。
因?yàn)槭腔赿om節(jié)點(diǎn)來生成的吞滞,所以樣式千萬不能寫display: none,visibility: hidden盾沫,以及使用變量去控制是否展示裁赠。只能用z-index屬性來控制,因?yàn)閦-index只是隱藏起來赴精,顯示在圖層下面组贺,所以不影響生成圖片。
-
生成圖片大小及展示的內(nèi)容是根據(jù)你當(dāng)前屏幕拖動(dòng)來決定的祖娘,也就是說你當(dāng)前屏幕寬是450px失尖,那么生成的圖片寬度就是450px啊奄,超出寬度部分的內(nèi)容則不會(huì)顯示在圖片里。而且因屏幕拖動(dòng)擠壓的內(nèi)容也不會(huì)顯示(前提是你echarts做了resize圖表自適應(yīng)掀潮,或是頁面做了自適應(yīng))
生成圖片的內(nèi)容是根據(jù)你當(dāng)前id范圍來顯示的。
1 安裝插件
https://www.html2canvas.cn/html2canvas-about.html
npm install html2canvas
2 頁面引入使用
import html2canvas from "html2canvas";
- 全局生成圖片
<!-- 父組件 index -->
template>
<div>
<!-- 默認(rèn)生成尺寸 -->
<OriginalBoard @dataForFinalBoard="downloadImg" />
<!-- 固定寬度1270px -->
<FinalBoard2 :dataFromOriginalBoard="dataFromOriginalBoard"/>
</div>
</template>
<script>
import { OriginalBoard, FinalBoard2 } from './modules/index'
export default {
name: 'currentVipUser',
components: {
OriginalBoard,
FinalBoard2
},
data() {
return {
dataFromOriginalBoard: '', // 用于存儲(chǔ)從originalBoard接收的數(shù)據(jù)仪吧,并傳遞給FinalBoard
}
},
methods: {
downloadImg(data){
this.dataFromOriginalBoard = data; // 更新數(shù)據(jù)庄新,以便通過props傳遞給FinalBoard
}
}
}
</script>
<!-- OriginalBoard -->
<div
class="hour_box"
ref="oneHourImageDom"
>
<div class="current1">
<div class="current_title">
每小時(shí)支付情況
<span>(單位:萬)</span>
</div>
<div
class="gen_img"
@click="oneHourImg()"
v-if="!isShowSearch"
>
<span class="gen_title">生成圖片</span>
</div>
</div>
<!-- 柱狀圖 -->
<OneHourChart ref="oneHourChartData" />
</div>
<script>
import OneHourChart from './OneHourChart'
export default {
props: {
dataForFinalBoard: {
type: String,
default: ''
}
},
components: { OneHourChart },
created() {
this.init()
},
methods:{
init() {
// 這個(gè)入?yún)⒚總€(gè)接口都要傳參薯鼠,所以拿出來單獨(dú)寫择诈,不然每個(gè)接口都得重寫一遍
if (!this.timeRange) {
// 明分秒沒有值時(shí),日期后面加上23:59:59
this.queryParams.queryTime = moment(this.queryParams.queryTime).format('YYYY-MM-DD 23:59:59')
} else {
// 明分秒有值時(shí)出皇,把時(shí)分秒和日期拼接起來
this.queryParams.queryTime = moment(this.queryParams.queryTime).format('YYYY-MM-DD') + ' ' + this.timeRange
}
this.$nextTick(() => {
// 調(diào)接口
this.$refs.oneHourChartData.getOneHour(this.queryParams); // 每小時(shí)支付情況
})
},
oneHourImg() {
// Math.random 隨機(jī)數(shù)羞芍,可重復(fù)點(diǎn)擊生成圖片
const data = 'oneHourImg' + '_' + Math.random();
this.$emit('dataForFinalBoard', data);
}
}
}
</script>
<!-- FinalBoard2-->
<div
class="hour_box"
ref="oneHourImageDom"
>
<div class="current1">
<div class="current_title">
每小時(shí)支付情況
<span>(單位:萬)</span>
</div>
</div>
<OneHourChart ref="oneHourChartData" />
</div>
<script>
import html2canvas from "html2canvas";
import OneHourChart from './OneHourChart'
export default {
props: ['dataFromOriginalBoard'], // 通過props接收來自父組件的數(shù)據(jù)
components: { OneHourChart },
// 監(jiān)聽到父組件index傳值過來觸發(fā)
watch:{
'dataFromOriginalBoard': {
immediate: true, // 如果需要組件實(shí)例化時(shí)立即觸發(fā)
deep: true,
handler(newVal, oldVal) {
// 切割隨機(jī)數(shù)
newVal = newVal.split('_')[0]
if(newVal == 'oneHourImg'){
this.oneHourImg();
}
}
}
},
methods:{
oneHourImg() {
html2canvas(this.$refs.oneHourImageDom, {
backgroundColor: '#202020',
}).then(canvas => {
var img = canvas.toDataURL("image/png");
var a = document.createElement("a");
a.href = img; // 將生成的URL設(shè)置為a.href屬性
a.download = "每小時(shí)支付情況.png";
a.click();
a.remove(); // 下載完成移除a標(biāo)簽
});
}
},
}
</script>
- OneHourChart組件
<template>
<div
id="oneHour"
ref="oneHour"
class="hour_charts"
v-loading="oneHourLoading"
element-loading-background="rgba(0, 0, 0, 0.8)"
></div>
</template>
<script>
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import { hourPayAmt } from "@/api/xxx";
export default {
props: {},
data() {
return {
oneHourLoading: false,
oneHourChart: null, // 每小時(shí)支付情況
}
},
mounted() {
// echarts圖表自適應(yīng)
window.addEventListener('resize', this.resize); // 添加監(jiān)聽
},
destroyed() {
// 移除監(jiān)聽,echarts自適應(yīng)
window.removeEventListener('resize', this.resize)
},
methods: {
resize() {
this.oneHourChart.resize();
},
getOneHour(queryParams) {
this.oneHourLoading = true;
hourPayAmt(queryParams).then(({ code, data }) => {
if (code == 0) {
// this.$refs.oneHour這樣寫是因?yàn)榻涌谝{(diào)用2次郊艘,不然會(huì)提示dom已加載渲染
this.oneHourChart = echarts.init(this.$refs.oneHour);
const option = {
tooltip: {
trigger: 'axis',
extraCssText: 'background: linear-gradient( 321deg, #FDFEFF 0%, #F4F7FC 100%);',
formatter: function (params) {//提示內(nèi)容
let relVal = '<div style="margin-bottom:4px;font-size:12px;color:#1D2129;">' + params[0].name + '</div>';
for (let i = 0; i < params.length; i++) {
relVal += `
<div style="font-size:12px;min-width:164px;height:32px;background:rgba(255,255,255,0.9);box-shadow: 6px 0px 20px 0px rgba(33,87,188,0.1);margin-bottom:4px;border-radius:4px;display:flex;align-items:center;justify-content:space-between;padding: 0 8px;box-sizing:border-box;">
<span style="color:#4E5969;margin-right:10px;">
<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background: #0D34FF;margin-right:5px;"></span>`
+ params[i].seriesName + `</span><span style="font-size:13px;color:#1D2129;">` + params[i].data + `</span>
</div>`
}
return relVal;
},
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: true, // 坐標(biāo)軸兩邊留白策略
data: data.map(item => item.hour + ':00'),
axisLine: {
lineStyle: { color: '#717579' },
},
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: { color: '#8E8EA1' },
},
splitLine: { //網(wǎng)格線
lineStyle: {
color: '#2B2B2B',
type: 'dashed', // 線型為虛線
}
},
},
series: [
{
name: '支付金額',
type: 'bar',
barWidth: '20%', // 可以是具體像素值 '20px' 或百分比 '50%'
data: data.map(item => item.amt),
label: {
show: true, // 顯示數(shù)據(jù)
position: 'top', // 數(shù)據(jù)顯示的位置
textStyle: { // 字體樣式
color: '#FFFFFF', // 標(biāo)簽字體顏色
fontSize: 14, // 標(biāo)簽字體大小
}
},
itemStyle: {
borderRadius: [10, 10, 0, 0], //(順時(shí)針左上荷科,右上,右下纱注,左下)
color: new echarts.graphic.LinearGradient(0, 0, 0.7, 1, [
{ offset: 0, color: '#0D34FF' },
{ offset: 0.2, color: '#0DC2FF' },
{ offset: 1, color: '#202020' }
]),
},
},
],
};
this.oneHourChart.setOption(option);
}
}).finally(() => {
this.oneHourLoading = false;
});
},
}
}
</script>
<style src="@/assets/styles/salesBoard.scss" lang="scss" scoped></style>
待補(bǔ)充:
- 針對(duì)echarts圖表生成圖片(生成固定寬度畏浆,并且內(nèi)容全部展示),可以在echarts圖表里設(shè)置
getOneHour(queryParams) {
this.oneHourLoading = true;
hourPayAmt(queryParams).then(({ code, data }) => {
if (code == 0) {
this.oneHourChart = echarts.init(this.$refs.oneHour);
const option = {
tooltip: {
trigger: 'axis',
extraCssText: 'background: linear-gradient( 321deg, #FDFEFF 0%, #F4F7FC 100%);',
formatter: function (params) {//提示內(nèi)容
let relVal = '<div style="margin-bottom:4px;font-size:12px;color:#1D2129;">' + params[0].name + '</div>';
for (let i = 0; i < params.length; i++) {
relVal += `
<div style="font-size:12px;min-width:164px;height:32px;background:rgba(255,255,255,0.9);box-shadow: 6px 0px 20px 0px rgba(33,87,188,0.1);margin-bottom:4px;border-radius:4px;display:flex;align-items:center;justify-content:space-between;padding: 0 8px;box-sizing:border-box;">
<span style="color:#4E5969;margin-right:10px;">
<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background: #0D34FF;margin-right:5px;"></span>`
+ params[i].seriesName + `</span><span style="font-size:13px;color:#1D2129;">` + params[i].data + `</span>
</div>`
}
return relVal;
},
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: true, // 坐標(biāo)軸兩邊留白策略
data: data.map(item => item.hour + ':00'),
axisLine: {
lineStyle: { color: '#717579' },
},
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: { color: '#8E8EA1' },
},
splitLine: { //網(wǎng)格線
lineStyle: {
color: '#2B2B2B',
type: 'dashed', // 線型為虛線
}
},
},
series: [
{
name: '支付金額',
type: 'bar',
barWidth: '20%', // 可以是具體像素值 '20px' 或百分比 '50%'
data: data.map(item => item.amt),
label: {
show: true, // 顯示數(shù)據(jù)
position: 'top', // 數(shù)據(jù)顯示的位置
textStyle: { // 字體樣式
color: '#FFFFFF', // 標(biāo)簽字體顏色
fontSize: 14, // 標(biāo)簽字體大小
}
},
itemStyle: {
borderRadius: [10, 10, 0, 0], //(順時(shí)針左上狞贱,右上刻获,右下,左下)
color: new echarts.graphic.LinearGradient(0, 0, 0.7, 1, [
{ offset: 0, color: '#0D34FF' },
{ offset: 0.2, color: '#0DC2FF' },
{ offset: 1, color: '#202020' }
]),
},
},
],
};
this.oneHourChart.setOption(option);
if (queryParams.imgFlag) {
var image = document.getElementById('oneHour').style.width;
document.getElementById('oneHour').style.width = '1300px';
// 然后瞎嬉,立即調(diào)用 resize 方法更新圖表大小
this.resize()
this.oneHourLoading = false;
var imageURL = this.oneHourChart.getDataURL({
// 指定圖片導(dǎo)出的格式将鸵,'png', 'jpeg' 等
type: 'png',
// 導(dǎo)出的圖片分辨率比例,默認(rèn)為 1
pixelRatio: 1,
// 導(dǎo)出的圖片背景色佑颇,默認(rèn)不設(shè)置為透明背景
backgroundColor: '#fff'
});
var downloadLink = document.createElement('a');
downloadLink.href = imageURL;
downloadLink.download = 'echarts-image.png';
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
document.getElementById('oneHour').style.width = image;
console.log(window.innerWidth);
// 然后,立即調(diào)用 resize 方法更新圖表大小
this.resize()
}
}
}).finally(() => {
this.oneHourLoading = false;
});
},
- 生成圖片后賦值給img(固定寬度)
<div
class="hour_box"
ref="oneHourImageDom"
>
<div class="current1">
<div class="current_title">
每小時(shí)支付情況
<span>(單位:萬)</span>
</div>
<div
class="gen_img"
@click="oneHourImg()"
v-if="!isShowSearch"
>
<span class="gen_title">生成圖片</span>
</div>
</div>
<!-- 柱狀圖 -->
<OneHourChart ref="oneHourChartData" />
</div>
<img id="testimg" style="width: 1300px;height: auto;" />
<!-- OriginalBoard -->
oneHourImg() {
html2canvas(this.$refs.oneHourImageDom,{
backgroundColor: '#202020',
useCORS: true, // 允許跨域圖片下載
}).then(canvas => {
// 下載生成原有圖片(屏寬)
var originalImg = canvas.toDataURL("image/png");
var a = document.createElement("a");
a.href = originalImg; // 將生成的URL設(shè)置為a.href屬性
a.download = "每小時(shí)支付情況.png";
// 原生成的圖片賦值給最終顯示的canvas(width:1270px)
// const originalImgSize = new Image();
// originalImgSize.src = originalImg;
document.getElementById('testimg').src = originalImg
html2canvas(document.getElementById('testimg'),{
backgroundColor: '#202020',
useCORS: true // 允許跨域圖片下載
}).then(canvass => {
var img = canvass.toDataURL("image/png");
var a = document.createElement("a");
a.href = img;
a.download = "每小時(shí)支付情況.png";
a.click();
a.remove();
})
// originalImgSize.onload = () => {
// console.log('Image Width:', originalImgSize.width);
// console.log('Image Height:', originalImgSize.height);
// }
});
},