鑒於找我討論坑點的同仁比較多,直接建了交流群,歡迎大家加入:
畢竟眾人拾柴火焰高,有可能你遇到的問題就是別人已經解決的。
(若二維碼失效,加我好友【二維碼沒過期請自行加群,不用添加好友~】(微信號:),加好友請輸入暗號:html2canvas填坑群,拉你進群)
因為萬惡的廣告份子總是進群撒廣告、然后加我好友騷擾!這種技術群也進來撒廣告!實在很過分!!所以連夜緊急去掉微信二維碼和我的微信號了(現在是凌晨1:35~悲哀😭)。
實在想加群的,掃碼右邊的公眾號二維碼(或搜索“前端說吧”)后,回復“html2canvas”獲得加群二維碼,如果碼過期我又沒及時維護,可以回復“加群”,得到我微信二維碼后,加我好友並備注“html2canvas填坑群”~拉你進群。如果備注信息不對,我就不一 一通過啦見諒哈~

截圖模糊
原理就是講canvas畫布的width和height放大兩倍。
后來學習canvas的時候,才了解到這種寫法不同於css的寬高設置,
因為css里的只是展示畫布顯示的大小,不像這樣是canvas真正的內里圖畫分辨率的大小。
/*圖片跨域及截圖模糊處理*/
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()
元素設置文字陰影,截圖后陰影錯亂,所有元素都會有陰影
起初以為是v1.0.0-alpha.12 最新版本的問題,后來改成5也不行,把文字陰影去掉就可以了。
這個問題在大神的博文中有解決方案:https://blog.csdn.net/SDUST_JSJ/article/details/78122610
以下為針對本問題的部分摘錄:
文本設置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;
解決方案
針對這兩行的正則表達式,我添加了針對小數的判斷,修改后的代碼如下:
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
這種情況,之前同事遇到過,問我我說沒遇到過,后來找產品協調不要省略號。然后也沒當回事。


![]()

1 h5 一、有省略號無padding的正常情況 2 .box#targetEleId1 3 .text-box 1、為了出現省略號,我是一大段文字我為了出現省略號,我是一大段文字我 4 #btn1 點擊我 5 h5 二、有省略號。加了padding的正常情況 6 .box#targetEleId2 7 .text-box.text-box2 2、為了出現省略號,我是一大段文字我為了出現省略號,我是一大段文字我 8 #btn2 點擊我 9 h5 三、省略號用偽類模擬的情況 10 .box#targetEleId3 11 .text-box3 3、為了出現省略號我是一大段文字我為了出現省略號,我是一大段文字我 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 }
隨便寫的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 (持續更新中...)
