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è)兄弟組件的樣式共用一份害捕,如對(duì)生成圖片的頁面顯示有要求的話绿淋,可以再單獨(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. 針對(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;
      });
    },
  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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末草娜,一起剝皮案震驚了整個(gè)濱河市挑胸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宰闰,老刑警劉巖茬贵,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異移袍,居然都是意外死亡解藻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門葡盗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來螟左,“玉大人,你說我怎么就攤上這事〗罕常” “怎么了巷嚣?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)钳吟。 經(jīng)常有香客問我廷粒,道長(zhǎng),這世上最難降的妖魔是什么红且? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任坝茎,我火速辦了婚禮,結(jié)果婚禮上暇番,老公的妹妹穿的比我還像新娘嗤放。我一直安慰自己,他們只是感情好奔誓,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布斤吐。 她就那樣靜靜地躺著,像睡著了一般厨喂。 火紅的嫁衣襯著肌膚如雪和措。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天蜕煌,我揣著相機(jī)與錄音派阱,去河邊找鬼。 笑死斜纪,一個(gè)胖子當(dāng)著我的面吹牛贫母,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盒刚,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼腺劣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了因块?” 一聲冷哼從身側(cè)響起橘原,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涡上,沒想到半個(gè)月后趾断,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吩愧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年芋酌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雁佳。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脐帝,死狀恐怖同云,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腮恩,我是刑警寧澤梢杭,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站秸滴,受9級(jí)特大地震影響武契,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荡含,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一咒唆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧释液,春花似錦全释、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至寝蹈,卻和暖如春李命,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背箫老。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工封字, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人耍鬓。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓阔籽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親牲蜀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子笆制,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容