html2canvas - 項目中遇到的那些坑點彙總(更新中...)

 截圖模糊javascript

    原理就是講canvas畫布的width和height放大兩倍。css

  後來學習canvas的時候,才瞭解到這種寫法不一樣於css的寬高設置,html

  由於css裏的只是展現畫布顯示的大小,不像這樣是canvas真正的內裏圖畫分辨率的大小。java

/*圖片跨域及截圖模糊處理*/
      let shareContent = domObj,//須要截圖的包裹的(原生的)DOM 對象
          width = shareContent.clientWidth,//shareContent.offsetWidth; //獲取dom 寬度
          height = shareContent.clientHeight,//shareContent.offsetHeight; //獲取dom 高度
          canvas = document.createElement("canvas"), //建立一個canvas節點
          scale = 2; //定義任意放大倍數 支持小數
      canvas.width = width * scale; //定義canvas 寬度 * 縮放
      canvas.height = height * scale; //定義canvas高度 *縮放
      canvas.style.width = shareContent.clientWidth * scale + "px";
      canvas.style.height = shareContent.clientHeight * scale + "px";
      canvas.getContext("2d").scale(scale, scale); //獲取context,設置scale 
      let opts = {
          scale: scale, // 添加的scale 參數
          canvas: canvas, //自定義 canvas
          logging: false, //日誌開關,便於查看html2canvas的內部執行流程
          width: width, //dom 原始寬度
          height: height,
          useCORS: true // 【重要】開啓跨域配置
      };
html2canvas(shareContent,opts).then() 

  

元素設置文字陰影,截圖後陰影錯亂,全部元素都會有陰影nginx

  起初覺得是v1.0.0-alpha.12 最新版本的問題,後來改爲5也不行,把文字陰影去掉就能夠了。git

  這個問題在大神的博文中有解決方案:https://blog.csdn.net/SDUST_JSJ/article/details/78122610github

  

如下爲針對本問題的部分摘錄: web

 文本設置text-shadow截圖後卻沒有文本陰影(2017-09-28)

  bug緣由

  查看了源碼,html2canvas確實處理了text-shadow,可是沒有正確的處理小數,致使最後文本陰影沒有顯示出來。 
  具體的代碼爲第1762行正則表達式

NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;
NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;

  解決方案

  針對這兩行的正則表達式,我添加了針對小數的判斷,修改後的代碼以下:canvas

NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+(?:\.\d+)?px){0,})/g;
NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+(?:\.\d+)?px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;

  測試:

// html2canvas正則匹配
'rgb(102, 102, 102) 11.924px 11.924px 0px'.match(/((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g); // ["rgb(102, 102, 102)"]
"rgb(102, 102, 102) 11.924px 11.924px 0px".match(/(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g); // ["rgb(102, 102, 102)", "924px", "924px", "0px"]

// 修改後的正則匹配
'rgb(102, 102, 102) 11.924px 11.924px 0px'.match(/((rgba|rgb)\([^\)]+\)(\s-?\d+(?:\.\d+)?px){0,})/g); // ["rgb(102, 102, 102) 11.924px 11.924px 0px"]
"rgb(102, 102, 102) 11.924px 11.924px 0px".match(/(-?\d+(?:\.\d+)?px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g); // ["rgb(102, 102, 102)", "11.924px", "11.924px", "0px"]

 文本陰影效果沒有顯示(2017-10-18)

  現象及緣由

  現象: 
    部分文本設置了陰影效果,可是截圖後並無顯示出來。 
  緣由: 
    html2canvas庫確實解析了陰影樣式,可是並無繪製,只是當作變量存起來了。 
  第2245行,解析的值是正確的:

this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);

  第3044行能夠看出,只是存起來了,並無繪製:

 this.setVariable("shadowColor", color.toString())
     .setVariable("shadowOffsetY", offsetX)
     .setVariable("shadowOffsetX", offsetY)
     .setVariable("shadowBlur", blur);

  解決方案

  使用canvas context提供的陰影方法繪製陰影: 
  第3044行,將fontShadow 函數改成以下所示:

CanvasRenderer.prototype.fontShadow = function(color, offsetX, offsetY, blur) {
  this.ctx.shadowOffsetX = offsetX;
  this.ctx.shadowOffsetY = offsetY;
  this.ctx.shadowColor = color;
  this.ctx.shadowBlur = blur;
};

CanvasRenderer.prototype.clearShadow = function() {
    this.ctx.shadowOffsetX = 0;
    this.ctx.shadowOffsetY = 0;
    this.ctx.shadowBlur = 0;
};

  

文本描邊和陰影同時顯示時顯示不正常(2017-10-18)

  現象及緣由

  現象: 
    陰影特別嚴重,甚至看起來有點模糊。 
  緣由: 
    和canvas context什麼時候調用strokeText方法有關。具體緣由在解決方案中描述。

  解決方案(2017-10-19修改)

  第2251行第2242行改成以下所示代碼:

this.renderer.font(container.parent.color('color'), container.parent.css('fontStyle'), container.parent.css('fontVariant'), weight, size, family);
    // if (shadows.length) {
    //     // TODO: support multiple text shadows
    //     this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);
    // } else {
    //     this.renderer.clearShadow();
    // }

    this.renderer.clip(container.parent.clip, function() {
        textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) {
            if (bounds) {
                if (shadows.length) {
                  this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);
                  this.renderer.text(textList[index], bounds.left, bounds.bottom);
                  this.renderer.clearShadow();
                  this.renderTextStroke(textList[index], container.parent, bounds, this.fontMetrics.getMetrics(family, size));
                  this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
                } else {
                  this.renderer.text(textList[index], bounds.left, bounds.bottom);
                  this.renderTextStroke(textList[index], container.parent, bounds, this.fontMetrics.getMetrics(family, size));
                  this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
                }
            }
        }, this);
    }, this);

  若是有陰影,一開始就渲染stroke,以後的內容會覆蓋一部分stroke的內容;若是沒有陰影,最後渲染stroke,stroke會覆蓋filltext函數渲染的內容。 
  先渲染text,若是有陰影,同時渲染陰影,而後將陰影效果去掉;若是有描邊,渲染描邊效果。經確認,這種寫法比以前的寫法要好。(2017-10-19)

  以上摘自:

  csdn   https://blog.csdn.net/SDUST_JSJ/article/details/78122610

  做者: kylin_zdd1993

 

水平居中的元素截圖後向左跑偏

  明明是水平居中的代碼,截圖出來的會偏左,結構是左圖片右文字,有時候是圖片本身跑到最左邊,有時候是總體偏左一點點
  這個問題也不是常常遇到,場景是父div元素text-align=center;內部兩個子元素設爲display:inline-block的模式。而後畫圖就會出現左邊的div偏左靠或直接在左邊的狀況。
  問題未解決,出現時也沒研究由於啥,等有時間的時候就不出現了。。。

 

靠背景圖露臉的dom們會有底線。即若是元素使用背景圖呈現,那麼截圖完畢會有一條下邊線
  截圖時,若是有一個dom元素是用背景圖填充的,裏邊沒有任何結構,那麼截圖出來的底部會有一條和背景圖底部一致的一條線

  像是背景圖y軸重疊,而後差那麼一像素沒鋪滿的感受。

   好比這樣一張圖:

  

  截出來長這樣:

   

  項目暫時解決方法,藍色背景用顏色不用整塊的圖片顯示。

  這種圖片廣泛有一個規律就是,有投影,圖片的正常高度要高於有顏色區域的高度

  如這張圖:

 

  底部部分:

 

  有時候靠拉伸/壓縮一點點dom元素的高度解決了,有時候又不行。

 

背景圖作的元素,截圖出來圖也是很模糊的,設置倍數也沒用。

 在iphone 7plus中,即便沒有背景圖截出來的仍是有一條邊線...

 

下邊是黑色背景色+小點點,就這樣的佈局,一個背景色都沒有,爲何截圖下來仍是有條線?並且仍是部分手機中的ip7!

 

the operation is insecure
    canvas.toDataURL 報錯 the operation is insecure
  canvas.toDataURL(type, encoderOptions);語法
  配置如:canvas.toDataURL("image/png", 0.7);
  參數type指定圖片類型,若是指定的類型不被支持則以默認值image/png替代;
  encoderOptions(第二個參數)能夠爲image/jpeg或image/webp類型的圖片設置圖片質量,取值0-1,超出則以默認值0.92替代。


html2canvas在微信中base64碼爲空
    在微信中或者能夠說在移動端瀏覽器裏,canvas.toDataURL不成功。canvas.toDataURL(type) 獲得空的 data:;
  折騰了半天。。。
  同事說若是base64碼的長度有個限制,忘了超過多少就不行了,後來我嘗試把放大四倍改爲放大兩倍,問題居然解決了!!
  不要笑話我放大了四倍,爲了清晰哈哈哈。可是改爲兩倍後和四倍比也沒差。反卻是挖了個坑本身填了半天!

 

不可見的元素截圖後是空白
    無法截圖看不見的,好比opacity爲0的東西,或者visibility爲hidden的,更別說display:none了。都不行,
  截出來的同樣是白色的,可想而知,畢竟沒截上東西固然就是白色了。
  解決方法是讓canvas部分隱藏到後邊。最終選擇方案,層級設爲-1,上一層的把他蓋住。

  前提是上一層要又一個能夠設置的背景色,能把他蓋住不被世人看到

 

html2canvas結合微信裏的長按存圖功能
  先用html2canvas拿到一個html轉爲canvas的base64碼,

  再在頁面創建一個img元素,src=base64碼,插入dom中,蓋在全部元素的最上方(或者須要用戶長按保存的地方),opacity設置爲0。

  而後用戶就長按保存,存下來的就是事先準備好的覆蓋在那裏的那個不可見得透明圖。
  事實證實,圖片透明不可見覆蓋在頁面上邊,微信裏是能夠存圖的。

  而不少市面上的h5,結果頁和最後存下來的圖不同的,估計都是這麼搞得,畢竟看不見代碼

 

html2canvas+jsbridge同時存兩張圖
    html2canvas和jsbridge的存圖功能協做時,會觸發同時存兩張圖的現象。

  第一次存圖很完美,若是不關掉頁面第二次存圖,就會存兩張,之後也會存兩張。只有第一次使用存圖是好的。
  就是jsbridge調了兩次,第二次自動調起的緣由目前猜想是html2canvas引發的, 

  由於一層層定位,只有在html2canvas返回base64碼後會有問題。具體緣由暫沒有找到。
  最後解決方法是:配合sessionStore,第一次截完圖後,將圖片地址存入sessionstore,

  以後判斷,sessionstore裏有base64碼就不用html2canvas生成碼了,直接取數據存圖,

 

html2canvas觸發時從新加載頁面的全部靜態資源(除js)
  css和img圖像,這一點是在和Wdatapicker組合使用時發現的問題。

  原本沒什麼,愛加載幾回加載幾回,可是datapicker的樣式是寫在iframe裏的,從新加載dom還把人家的樣式給丟了。這事兒就大了
  大歸大,問題根本緣由沒解決,仍是治標不治本的在每次觸發html2canvas截圖保存pdf的時候,從新給datapicker繪製樣式,就是這麼任性!

 

html2canvas 截圖跨域

  圖片跨域時報錯現象

  

 

  這個時候你要去看圖片的header頭有沒有這個:

  看圖片自己是否容許跨域訪問:

  

  上邊這個是一個容許的圖片。

  下邊這個不容許,就截取不到。

  

  

    這篇博文對於html2canvas跨域講解很細緻: https://blog.csdn.net/yaosir1993/article/details/76474080

  如下截取部分做者思想,主要是用於解決了本次問題的地方:
  useCORS:true 這個參數很重要,沒有配置的話,依舊是不能解決問題的;
  根據現有的解決方案大體有兩種:
  (1).在跨域的服務器上設置header設置爲容許跨域請求。 在服務器上設置header設置容許跨域請求(採用nginx作靜態資源映射) 
  (2).藉助代理腳本得到外域圖片的 base64 編碼後的字符串
  
  關於跨域和清晰度解決方案的講解地址:https://lengxing.github.io/
  設置header,實現跨域訪問http://blog.csdn.net/enter89/article/details/51205752 

 

  解決建議:

  域名反向代理,

  圖片容許跨域使用:Access-Control-Allow-Origin: *;

 

html2canvas+qrcode 截二維碼被白底遮擋(有背景設置的元素截圖後,背景色把圖片蓋住)

  html2canvas執行截圖-由於頁面中有一處是qrcode執行的地址轉二維碼,每次截圖後二維碼都截不下來,那一塊就是一個白塊.

  按理說二維碼圖片是base後的地址不該該啊。

  後來把二維碼img的外部div元素的背景色設置半透明,二維碼就隱約能看出來了,原來是div的背景色蓋住了img。
  原理仍是搞不明白,明明層級都設置了還不起做用,居然被本身的爹給蓋住也是醉了。
  二維碼處之因此爲白色是由於外部結構的白色背景給覆蓋了,最後是盛放二維碼img的外部div結構不設置背景色就解決了


html2canvas截圖時,背景音樂在IOS11下會重複播放
  解決方法見博文:https://blog.csdn.net/lerayZhang/article/details/79207468

 

震驚!html2canvas截圖,省略號失蹤?!

     2018-09-27 17:49:09

  這種狀況,以前同事遇到過,問我我說沒遇到過,後來找產品協調不要省略號。而後也沒當回事。

    最近又被博友問起,我恰好在作相似項目,就順手模擬了一下效果,以下:

   

  而後不出意料的出現了幾個堪比車禍現場的問題:
  請看三種的依次截圖效果:
  

  

  

 

  其一固然是本問題主題,即 省略號丟失的問題
  其二請觀察圖二,你會發現, 用了padding的元素,他的截圖中,左padding還在,右padding沒了,而是被文字給填充了.
 
  先說回省略號的問題,我猜測和canvas機制有關,
  由於畢竟canvas裏邊繪製文字不會換行,
  而後html2canvas多是獲取文本進行的fillText/strokeText()的繪製,而省略號並非實際dom結構中的文本。因此獲取不到?
 
  突發奇想, 那僞類裏邊的content的內容他能夠拿到嗎?答案是能夠。
  在圖三中,我將省略號做爲僞類的內容, 利用僞類模擬超出顯示省略號的效果進行截圖,最後省略號截了下來.
  加上以往經驗能夠說明,內容放在僞類中也是能夠被拿到的。因此我剛纔  對於僞類不能被截下來的設想能夠消滅。放心大膽的用僞類吧!
 
  可是可是,問題仍是沒解決額, 這種模擬的效果太脆弱了吧!
  稍微文字多一個少一個標點,最後邊文字會由於 overflow:hidden;被截成半塊。你看

  

  因此在這裏只是爲了拋轉引玉,
  有了這個模擬省略號的思路後,不知道各位看官大佬們還有更好的方法解決這個問題嘛?
  能夠作到既不讓省略號消失,也不讓實際文字內容被劈成兩半?
  
  拋磚引玉的代碼:
 1 h5 1、有省略號無padding的正常狀況
 2         .box#targetEleId1
 3           .text-box 一、爲了出現省略號,我是一大段文字我爲了出現省略號,我是一大段文字我
 4         #btn1 點擊我
 5         h5 2、有省略號。加了padding的正常狀況
 6         .box#targetEleId2
 7           .text-box.text-box2 二、爲了出現省略號,我是一大段文字我爲了出現省略號,我是一大段文字我
 8         #btn2 點擊我
 9         h5 3、省略號用僞類模擬的狀況
10         .box#targetEleId3
11           .text-box3 三、爲了出現省略號我是一大段文字我爲了出現省略號,我是一大段文字我
12         #btn3 點擊我
13         style.
14           h5{
15             margin-top:30px;
16           }
17           .text-box{
18             margin-right: .2rem;
19             overflow: hidden;
20             text-overflow: ellipsis;
21             white-space: nowrap;
22             background: #c3e2c3;
23           }
24           .text-box2{
25             padding: 1rem;
26           }
27           #targetEleId3{
28             background: #c3e2c3;
29             position: relative;
30           }
31           #targetEleId3:after{
32             content: "...";
33             position:absolute;
34             right: 0.1rem;
35             top: 0;
36             display: inline-block;
37           }
38           .text-box3{
39             overflow: hidden;
40             padding-right: .2rem;
41             margin-right: 0.3rem;
42             white-space: nowrap;
43           }
44           body{
45             padding-bottom: 1rem;
46           }
html+css

   隨便寫的js:

import {html2img} from '../html2img' 
// 引入html2canvas封裝代碼:html2img
const oBtn1 = document.getElementById('btn1');
const  targetEleId1 = document.getElementById('targetEleId1');
const oBtn2 = document.getElementById('btn2');
const  targetEleId2 = document.getElementById('targetEleId2');
const oBtn3 = document.getElementById('btn3');
const  targetEleId3 = document.getElementById('targetEleId3');
oBtn1.onclick = function(){
  html2img({
    targetEleId: targetEleId1,
    imgType: 'jpg',
    titleStr: '自定義圖片名稱_當前時間戳'
  },false)
  .then((imgUrl)=>{
  // 拿到返回值:base64後的圖片地址:imgUrl。執行其餘邏輯
    var myImg = document.createElement('img');
    myImg.src=imgUrl;
    myImg.style.marginBottom=100+'px';
    myImg.style.marginLeft=10+'px';
    document.body.appendChild(myImg)
  })
};
oBtn2.onclick = function(){
  html2img({
    targetEleId: targetEleId2,
    imgType: 'jpg',
    titleStr: '自定義圖片名稱_當前時間戳'
  },false)
  .then((imgUrl)=>{
  // 拿到返回值:base64後的圖片地址:imgUrl。執行其餘邏輯
    var myImg = document.createElement('img');
    myImg.src=imgUrl;
    myImg.style.marginBottom=100+'px';
    myImg.style.marginLeft=10+'px';
    document.body.appendChild(myImg)
  })
};
oBtn3.onclick = function(){
  html2img({
    targetEleId: targetEleId3,
    imgType: 'jpg',
    titleStr: '自定義圖片名稱_當前時間戳'
  },false)
  .then((imgUrl)=>{
  // 拿到返回值:base64後的圖片地址:imgUrl。執行其餘邏輯
    var myImg = document.createElement('img');
    myImg.src=imgUrl;
    myImg.style.marginBottom=100+'px';
    myImg.style.marginLeft=10+'px';
    document.body.appendChild(myImg)
  })
};

  

 

 

  

 

 

 

 

 

重點說明:

  通過這幾回的html2canvas填坑記,我發現,使用html2canvas@1.0.0-alpha.5版本,配套上咱們本身封裝的html2img,總算坑能夠少點了。正常的需求仍是能夠實現了。

  另外,我是女的,加QQ別上來就喊哥們兒了[捂臉]。雖然我比較漢子,但我不想真漢哈哈哈~

  2018-06-25  17:54:43  (持續更新中...)

相關文章
相關標籤/搜索