html2canvas生成固定寬度圖片(內(nèi)容完全顯示)

最終效果圖
需求

html2canvas生成圖片,不會(huì)隨著屏幕窗口rize大小變化而變化,但頁面上是正常顯示 。無論移動(dòng)端或pc端都生成固定寬度(1300px),且生成內(nèi)容完全展示,這個(gè)寬度根據(jù)自己的需求變化。

實(shí)現(xiàn)思路
  1. 父頁面寫兩個(gè)一樣的兄弟組件OriginalBoard和FinalBoard2
  2. OriginalBoard組件默認(rèn)正常顯示
  3. FinalBoard2組件隱藏(使用z-index)
  4. OriginalBoard組件觸發(fā)點(diǎn)擊按鈕,把值傳給父組件index,再通過index傳給FinalBoard2
  5. 兩個(gè)兄弟組件的樣式共用一份,如對生成圖片的頁面顯示有要求的話,可以再單獨(dú)修改。
用html2canvas生成圖片需要特別注意以上幾點(diǎn):
  1. 生成圖片是基于dom節(jié)點(diǎn)來生成的。

  2. 因?yàn)槭腔赿om節(jié)點(diǎn)來生成的,所以樣式千萬不能寫display: none,visibility: hidden,以及使用變量去控制是否展示只能用z-index屬性來控制,因?yàn)閦-index只是隱藏起來,顯示在圖層下面,所以不影響生成圖片。

  3. 生成圖片大小及展示的內(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))


    拖動(dòng)屏幕時(shí)會(huì)擠壓數(shù)據(jù),展示不全
  4. 生成圖片的內(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ǔ)充:

  1. 針對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;
      });
    },
  1. 生成圖片后賦值給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);
        // }
      });
    },

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容