前言:需要做一個微信端的h5小活動,最后要生成一個包含用戶微信頭像、昵稱及一些其他圖片的頁面,并將頁面以圖片的形式保存下來(長按保存)。
實現(xiàn)效果:
因為是微信內(nèi)置瀏覽器,保存功能還是需要用戶長按圖片,調(diào)起微信內(nèi)置菜單來完成,所以,在頁面記載完成時,圖片就已經(jīng)生成了(因為我這邊要求最后保存到手機的圖和用戶當(dāng)前看的結(jié)果圖并不相同,所以我另外做了個層級遮蓋,欸,貍貓換太子。這里就不做贅述了)。
用到的當(dāng)然還是受到廣泛歡迎的html2canvas,但是坑好多。。。
遇到的坑
- border
在頭像設(shè)置了圓角后,在外面加border,沒有效果。解決方法很容易,在頭像的img標(biāo)簽外套一層div,將div設(shè)置背景色(就是你想要的border顏色),然后加padding(就是border的寬度),就可以啦。。。。這個比較簡單,就不貼代碼啦 - 清晰度問題
這個網(wǎng)上有好多教程,教你設(shè)置canvas的scale,然后保存,但是這樣不夠靈活。我是這樣做的,原來的html部分的css該什么樣還是什么樣,但是我會再寫一份scale版本的,基本是放大2倍(有時可能不是剛好2倍,可以根據(jù)實際保存效果做調(diào)整)。css如下,html會在下面貼上,因為html過程中還有下面的一個坑
/*要存的區(qū)域*/
.pic-content{
position: relative;
width: 100%;
height:100%;
background-image: url(community-ad/community-certificate-bg.png);
background-size: 100% 100%;
padding: 80px 24% 0;
}
/*選中的照片*/
.pic-content .choosed-pic{
width: 100%;
background-image: url(community-ad/community-frame.png);
background-size: 100% 100%;
padding: 13px 17px;
margin-bottom: 10px;
}
/*一些其他元素*/
...
/*放大圖*/
.scale-content {
position: relative;
width: 200%;
height:200%;
background-image: url(community-ad/community-certificate-bg.png);
background-size: 100% 100%;
padding: 150px 28% 0;
}
/*選中的照片*/
.scale-content .choosed-pic{
width: 100%;
background-image: url(community-ad/community-frame.png);
background-size: 100% 100%;
padding: 26px 28px;
margin-bottom: 20px;
}
/*一些其他元素*/
...
- html2canvas默認以屏幕的寬為canvas的寬,當(dāng)需要轉(zhuǎn)化的html超出屏幕范圍時就只能轉(zhuǎn)化當(dāng)前可視部分,即上面scale-content部分設(shè)置width 200% 會超出。
html2canvas之所以獲取不到超出部分是因為對象element的父元素寬高不夠,也就是說只要將父元素的寬高設(shè)為和需要轉(zhuǎn)換為canvas的子元素的寬高一樣大就不會出現(xiàn)這個問題啦
所以,html頁面上,要把這塊拎出來,不能和pic-content放在同一父元素下。這邊做的是直接放body中
<div class="wb-content" v-cloak>
<div id="shareContent" class="pic-content hide">
<div class="choosed-pic">
<img id="img1" :src="sliders[pic]" />
</div>
...
</div>
<!--生成的圖片-->
<img v-if="url" class="new-pic" :src="url" />
<!--這里還可以寫一些其他需要的,可能要遮蓋的內(nèi)容,這里就不贅述了-->
...
</div>
<!--放大版canvas-->
<div id="scaleContent" class="scale-content"></div>
<script type="text/javascript">
//在轉(zhuǎn)之前要先這樣
var scaleContent=document.getElementById("scaleContent");
scaleContent.innerHTML=document.getElementById("shareContent").innerHTML;
</script>
- 當(dāng)然了,圖片跨域問題
在調(diào)用方法canvas.toDataURL("image/jpeg")時會遇到跨域的圖片,然后畫布就被tainted污染了。兩種:公司用來存圖片的是七牛,所以就是七牛服務(wù)器跨域;另一種是微信頭像的
網(wǎng)上關(guān)于這兩個的解決方式基本是圖片服務(wù)端設(shè)置允許跨域(返回 CORS 頭),html2canvas設(shè)置useCORS:true,//(圖片跨域相關(guān))allowTaint:false,//允許跨域(圖片跨域相關(guān));對于微信頭像,可通過配置服務(wù)端代理轉(zhuǎn)發(fā)(forward)實現(xiàn),此處不贅述。(關(guān)鍵是我不大懂服務(wù)器端的東西,總是覺得高大上)
這里用的方法是將文件讀入到blob文件對象,然后用URL.createObjectURL()方法轉(zhuǎn)換成img src可用的地址,然后再轉(zhuǎn)canvas。這樣不管是哪種跨域都可以直接解決
getImage:function (url,imgId) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'blob';
xhr.onload = function () {
if (this.status == 200) {
document.getElementById(imgId).src = URL.createObjectURL(this.response);
}
};
xhr.send();
},
最后貼上主要部分的完整代碼
<style type="text/css">
/*禁止滑動*/
body{overflow: hidden;}
.wb-content{width: 100%;height:100%;position: relative;}
.pic-content{
position: relative;
width: 100%;
height:100%;
background-image: url(img/community-certificate-bg.png);
background-size: 100% 100%;
padding: 60px 50px 0;
}
/*選中的照片*/
.pic-content .choosed-pic{
width: 100%;
background-image: url(img/community-frame.png);
background-size: 100% 100%;
padding: 13px 17px;
margin-bottom: 10px;
}
/*其他*/
...
/*放大圖*/
.scale-content {
position: relative;
width: 200%;
height:200%;
background-image: url(img/community-certificate-bg.png);
background-size: 100% 100%;
padding: 100px 100px 0;
}
/*選中的照片*/
.scale-content .choosed-pic{
width: 100%;
background-image: url(img/community-frame.png);
background-size: 100% 100%;
padding: 26px 34px;
margin-bottom: 10px;
}
...
</style>
<body>
<div class="wb-content" v-cloak>
<div id="shareContent" class="pic-content hide" >
<div class="choosed-pic">
<img id="img1" :src="getImage(sliders[pic],'img1')" />
</div>
...
</div>
<img v-if="url" class="new-pic" :src="url" />
...
</div>
<!--放大版canvas-->
<div id="scaleContent" class="scale-content"></div>
</body>
<script type="text/javascript" charset="utf-8">
var vm;
$(function() {
vm = new Vue({
el:".wb-content",
data:{
pic:getUrlParam('pic'),//選中的愛心畫
url:'',//生成的圖片鏈接
sliders:sliperChild,//輪播圖
},
methods:{
//直接讀成blob文件對象
getImage:function (url,imgId) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'blob';
xhr.onload = function () {
if (this.status == 200) {
document.getElementById(imgId).src = URL.createObjectURL(this.response);
}
};
xhr.send(null);
}
},
mounted:function(){
var self = this;
self.$nextTick(function(){
//生成圖片
htmlToImg(function(url) {
self.url=url
})
});
}
});
});
//轉(zhuǎn)存圖片
function htmlToImg(success){
//進度條
showWaiting();
//延時1000ms,等待圖片讀入到blob文件對象,然后使用URL.createObjectURL轉(zhuǎn)換成src可用的地址
setTimeout(function () {
//放大版html
var scaleContent=document.getElementById("scaleContent");
scaleContent.innerHTML=document.getElementById("shareContent").innerHTML;
//延時300ms,等待放大版html加載圖片完畢
setTimeout(function () {
//轉(zhuǎn)存圖片
html2canvas(scaleContent, {
useCORS: true, // 【重要】開啟跨域配置
allowTaint: true,//允許跨域圖片
taintTest: false,//是否在渲染前測試圖片
onrendered: function(canvas) {
scaleContent.innerHTML="";
scaleContent.remove();
var dataUrl = canvas.toDataURL("image/jpeg");
closeWaiting();
success&&success(dataUrl);
}
});
},300);
},1000);
}
</script>
還有需要改進的地方,請指出哈,不勝感激~~