移動端頁面分享快照生成總結

歡迎關注富途web開發團隊,php , 前端須要你。缺人從衆javascript

以前常常在微信中收到一些朋友分享帶頁面信息的圖片(分享圖片),這種分享方式相對於尋常的結構化分享(連接分享)更容易於表現頁面內容。公司的產品童鞋也想在活動頁面中生成一張分享圖片(帶用戶專屬二維碼的),引導用戶分享傳播。php

剛開始作這個功能時,咱們是由後端根據用戶的信息生成一張專屬的分享圖片,並將圖片上傳到圖片庫,得到圖片連接;再由前端調用接口後獲取到分享圖片的連接,在頁面中用img標籤展現這張圖片,配上一些引導的文案,提醒用戶「長按保存分享」。但考慮到服務器壓力、存儲等問題,咱們只會對一個用戶作一次分享圖片生成的操做(當用戶再一次獲取分享圖片的時候,返回的是第一次生成的那張圖片),即整個活動期間,單個用戶生成的分享圖片的內容是不會更改的。這樣就使得一些動態變化的數據不能展現在分享圖片中,分享圖片中可展現的內容受到很大的限制。css

後來,咱們想能不能直接有前端生成這張分享快照呢?前端生成圖片,無需通過網絡傳輸等操做,可減小服務的壓力,且能夠每次都動態生成圖片,可使分享圖片展現一些隨用戶操做而不斷變化的數據。以後發現已經存在一些html生成canvas或者img的庫,因此咱們就試了一下,看能不能直接由前端生成分享快照。html

簡單思路

html轉換爲image,(或者domcanvas再轉image),將生產的image的連接(多數是base64)放到頁面的img元素的src屬性上,再給出相關引導操做提示(如:長按保存圖片),引導用戶分享/保存圖片。前端

你們提起的htmlcanvasimage的庫主要有兩個:java

demo試驗

簡單的實例android

html代碼中,主要包括了根據設計童鞋給的分享快照的原稿重構出的分享快照的html代碼,和要放生成的圖片的img容器。ios

<div class="actShareBox">
  我是html!!
  <!-- 要用於生成快照的html代碼 -->
  <div class="j_snapshot snapshot">
  </div>
</div>
<div class="j_snapshot_img_box actShareImgBox">
    我是dom-to-image生成的圖片
    <!-- 用於展現dom-to-image生成的圖片 -->
    <img src="" class="j_snapshot_img">
</div>
<div class="j_snapshot_img_box actShareImgBox">
    我是html2canvas生成的圖片
    <!-- 用於展現html2canvas生成的圖片 -->
    <img src="" class="j_snapshot_img2">
</div>
複製代碼

在js代碼中,主要是調用兩個庫的API,生成圖片或者canvas。nginx

// $snapshot爲分享快照內容的dom元素,
// $snapshotImg爲要放domtoimage生成的圖片的img元素
// $snapshotImg2爲要放html2canvas生成的圖片的img元素
var $snapshot = document.querySelector('.j_snapshot');
var $snapshotImg = document.querySelector('.j_snapshot_img');
var $snapshotImg2 = document.querySelector('.j_snapshot_img2');

// domtoimage生成jpg的方法(這個庫還有其餘的方法)
domtoimage.toJpeg($snapshot,{
    quality: 1
}).then(function (dataUrl) {
    // 直接生成了base64的url
    $snapshotImg.src = dataUrl;
}).catch(function (error) {
    console.error('oops, something went wrong!', error);
});

// html2canvas 生成canvas
html2canvas($snapshot,{
    // useCORS: true, // 容許圖片跨域
    backgroundColor: null,
    logging: false,
}).then(function(canvas) {
    // 'image/jpeg', 1.0
    // 再利用canvas的toDataURL 方法,將canvas轉爲圖片
    var dataURL = canvas.toDataURL();
    $snapshotImg2.src = dataURL;
}, function(err) {
    console.error('oops, something went wrong!', err);
});
複製代碼

上圖...git

  • 在android微信中生成的圖片(小米note3)

    在android微信中生成的圖片

  • 在ios微信中生成的圖片(iphone6p)

    在ios微信中生成的圖片

從上面六張圖中能夠看出

  • 從生成的圖片內容的還原度看,不管在ios中或android中,html2canvas都能將分享圖片html頁面中內容完整的生成出來,而dom-to-image生成的圖片中,ios端生成的是一張殘缺的圖片(全部html頁面中圖片沒法正常的展現),在android也一樣有部分圖片沒法展現,且存在樣式錯亂問題。(這輪,html2canvas勝)

  • 從清晰度看,細看對比中間的圖(dom-to-image生成的圖片)和右邊的圖(html2canvas生成的圖片),能看出右圖中的文字、img圖片的清晰度都要比左圖的高不少(html中的背景圖片生成出來的清晰度,二者都不是很好)(這輪,仍是html2canvas勝)

so~, 仍是用html2canvas 吧。

遇到的問題

但使用html2canvas生成分享圖片時,仍是有遇到一些問題的,因此這裏將一些列出來。
剛開始用html/css重構分享快照時,咱們有用到純文本、img標籤圖片、css背景圖、對圖片/文字進行縮放。
第一次生成的圖片很不符合預期,生成的圖片與原圖效果相差較大。只能一一排查,尋找問題,解決問題了。

1.跨域圖片沒法展現

咱們的圖片資源是走cdn的,因此致使了圖片的連接域名與網頁的域名不一致,而產生了跨域問題,可能致使圖片沒法展現。

解決:
步驟1:將html2canvas中的參數設置中的useCORS屬性改成true,使html2canvas接受處理跨域資源。
步驟2: 使圖片資源容許跨域(響應頭中加上 Access-Control-Allow-Origin: *
這樣就能顯示跨域圖片了~

第三方跨域圖片處理:
本身的圖片實現容許跨域仍是比較容易的,但若是用到了第三方的不容許跨域的圖片(如微信頭像)呢,這時候須要咱們再多作一下處理,將那張圖片變成容許跨域的啦....

看別人的作法是:在服務器上實現第三方圖片的代理(將第三方圖片的域名變成本身的域名),再使本身的域名的資源容許跨域。

爲了一個活動而修改服務器的nginx配置,是否是不太好(慫=.=)。

因此咱們活動裏換了另外一種方式。

後端不直接返回微信頭像,而是一個能對應相關微信頭像的連接(這個連接的資源容許跨域),當後端接收到這個連接的請求時,拉取微信頭像信息,再返回給前端這個頭像的圖片信息。[這裏的後端指的活動中的後端代碼,與上面的改nginx配置不是一個作法]

後來發現,這個拉取微信頭像的操做有時會超時,因此咱們又作了層處理,在第一次獲取微信頭像後,將這個頭像上傳到本身的圖片庫中(異步操做),之後訪問頁面,須要微信頭像時,就返回圖片庫中的圖片連接(固然,這個圖片庫連接也是能夠跨域的)。

2.生成的分享圖片不清晰

這裏的不清晰指的有兩方面:

  1. 整張分享圖片的清晰度不夠
  2. 原分享頁面中的圖片在生成的分享圖片中的清晰度不夠

整張分享圖片清晰度不夠問題解決:
這裏的清晰度不夠的問題,是因爲圖片的實際物理像素點不夠的緣由形成的,這裏個人處理方法修改html2canvasscale屬性,增大繪製時的縮放比例,從而提升清晰度

html2canvas($snapshot, {
    useCORS: true,
    scale: window.devicePixelRatio*2 // 默認值是window.devicePixelRatio
    backgroundColor: null,
    logging: false
});
複製代碼

原分享頁面中的圖片在生成圖片中清晰度不夠問題解決

咱們在分享頁面中有用到兩種方式展現圖片:

  1. 使用img標籤元素引入圖片
  2. 使用元素中的背景圖片引入圖片

但從實際生成的圖片的效果發現,使用頁面中使用背景圖片的部分,在分享快照中會特別的不清晰,並且背景圖片的底部會有一些原頁面中沒有的小刺點(以下圖的背景圖裏,生成的圖片中富途logo下有一條相似的白色細線,但原頁面中卻沒有)。

而使用img標籤元素引入圖片則不會存在這種狀況。

  • 縮放過的背景圖片

    縮放過的背景圖片

  • img元素的圖片

    img元素的圖片

從圖中能夠看出,兩張圖的頁面截圖(上部分圖)顯示的清晰度是差很少的,但經過html2canvs生成圖片以後,明顯看出,背景圖的那張圖片的清晰度差好多,並且周圍還有些渣渣小點。

so: 若是分享快照中有用到圖片的話,仍是儘可能使用img標籤,而不是用背景圖,以保證分享圖片的清晰度。

分享圖片頁面中雪碧圖
在重構分享圖片頁面時,裏面有個vs的內容,裏面的陣營圖片會根據用戶的陣營選擇和最終獲勝陣營的結果而展現不一樣的內容,而咱們爲了頁面的性能問題,還有開發的方便,將這些陣營圖片拼成了一張雪碧圖,經過class控制展現不一樣的圖片。
一開始我也沒想到怎麼用img元素去展現雪碧圖,就仍是用了背景圖來顯示陣營選擇這塊內容,後來就時不時被產品童鞋吐槽分享圖片中那部份內容太模糊了....。

後來想了想,若是使用的是雪碧圖的話,也是能夠改爲用img標籤展現的:

<span class="emoji emoji01"><img src="/emoji.png" alt=""></span>

<style> .emoji{ width: 10px; height: 10px; /*固定大小,超過的隱藏*/ overflow: hidden; display: block; position: relative; } .emoji.emoji01 img{ position: absolute; /*使用top,left 偏移img圖片使之展現對應的位置*/ top: 0; left: -20px; } </style>
複製代碼

3.img 圖片對 transform屬性的兼容性不是很好

html2canvas的官方文檔中,有列了一些兼容性不是很好的css屬性,因此本身多測試一下,不能支持的屬性,就換一種寫法啦~。

在活動中遇到的是,img元素中的transform的實現不太好。

例子中是想將圖片居中展現,因此給img元素加了如下的css

img{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    width: 100%;
}
複製代碼

但實際上出來的效果是這樣的...。

img使用transform問題

總結

使用html2canvas,將頁面元素轉爲圖片的方式生成分享快照的方式是可行的,但在重構分享圖片頁面時,因儘量使用經常使用的方式和css屬性,少用背景圖片,就能生成一張清晰度不錯的圖片啦~。

原文:futu.im/article/cre…

做者:Cynthia

相關文章
相關標籤/搜索