作者:閑魚技術-苑振一
背景
分享是傳播活動,吸引使用者最重要的一環。現有分享手段多是題目配合單張圖檔,利用點選的方式跳轉到目标頁面。在資訊越來越豐富的今天,單個題目和圖檔對使用者的吸引力是有限的。而在對推廣要求更高的營銷場景和裂變過程中,我們往往需要将頁面内容一部分作為圖檔整體分享出去。直接利用手機原生的截屏功能會有幾個問題:1)内容格式無法自定義。2)翻頁情況無法處理。3)視窗區域不可控。本文通過讨論現有截屏的方案和閑魚内部截屏方案,介紹如何利用web實作移動端高還原度富圖文分享。
現有方案
Html2Canvas
介紹
html2canvas是一種基于canvas,将DOM結構繪制在canvas上面産生圖檔的第三方庫。通過如下的方式可以将對應的DOM結構繪制成圖檔儲存出來。優勢在于上手簡單,使用友善。
繪制原理
原理如下圖所示。核心邏輯是克隆對應節點DOM結構,利用parse解析成資料,建構canvas進行内容繪制,傳回對應的canvas。

實際使用過程中發現大概有如下幾個問題
- 圖檔跨域不支援。生成的圖檔存在跨域限制問題。
- 繪制清晰度低。即使使用api
放大後繪制,又會由于生成base64格式圖檔内容過長導緻無法傳輸。scale
- 圓弧計算精度低。由于html2canvas是計算像素後繪制到canvas上,而canvas展示又會經過浏覽器繪制,導緻像素精度降低。
- 深度節點出現黑色情況。由于DOM結構過深,經過像素計算後,會偶爾出現像素丢失情況。
SVG
該方案是利用svg可以包裹DOM結構的特性,将對應目标裝載進去,之後将svg導出成base64格式的圖檔。使用方式如下。通過xmlns指定命名空間,防止多集合下元素和屬性的沖突。字尾中的
svg
和
xhtml
分别表示解析方式。利用不同的解析方式,實作了svg内部嵌入html的方式。

之後隻要通過
encodeURIComponent(svg)
将對應的svg轉換成base64就可以。優勢是容易上手且不依賴第三方庫。
- SVG無法連接配接到外部的資源。比如通過cdn引入的css以及html中的圖檔連接配接都會被限制。
- 不支援js執行。現如今SPA頁面都需要執行JS後才會渲染對應的DOM節點,而SVG卻不支援JS的執行。
- SVG位置和大小不确定。遇到需要及時展示的情況,需要實時計算位置才行。
解決方案
思路
從上面可以看到,現有的兩種主流移動端截屏方案都有自己的不足。相比之下,利用canvas繪制的方法更适合SPA應用。那麼我們需要解決的是html2canvas對應的幾個問題:圖檔跨域,清晰度低,圓弧計算精度差,深層節點解析出錯。
圖檔跨域
通過
new Image()
的方式生成圖檔,在
image.onload
階段使用canvas繪制圖檔。此時會産生跨域限制,需要通過
crossOrigin = 'Anonymous'
設定來解決這個問題。

提高清晰度
在繪制中發現,如果采用寬度375px的canvas将圖檔導出,會出現圖檔模糊的情況。一種方案是提高原圖檔清晰度,但是加載速度會大大提高,使用者體驗不友好。另一種方式是放大canvas,利用
drawImage
中的參數控制圖檔坐标和canvas中的繪制坐标。
drawImage
中包含幾個參數:控制圖檔的sx, sy, sWidth, sHeight和控制canvas繪制的x, y, width, height。參數具體含義如圖中所示。

将方法中width和height乘上ratio,放大圖檔,控制繪制坐标,就能在canvas特定位置上繪制出想要的内容。考慮到小canvas在展示階段清晰度足夠,僅儲存階段需要放大三倍繪制的特性,采用第二種方法在幾乎沒有提高性能開銷的前提下,提高清晰度。我們以實際繪制截圖來看一下效果。下圖左邊是一倍結果,右圖是三倍結果。

圓弧精度提升和深層DOM解析
圓弧精度低和深層DOM解析出錯問題本質上還是由于DOM結構過于複雜,當采用通用方案處理時,難免無法覆寫。考慮到移動端内容有限,結構簡單的特點。決定采用特定DOM節點針對性繪制的方案解決深層DOM解析出錯的問題。好處如下:1)方法原子化,維護簡單。2)繪制高度自定義化,自由組織界面結構。3)拓展性強。在同僚胖仔的幫助下實作特定DOM節點繪制方案。方案建構過程中主要有如下幾個難點:圓角矩形,文字自動換行。
- 圓角矩形:通過截斷的方式繪制特定背景的圓角矩形。原理是通過
的方式在canvas上擷取圖檔内容,再利用Path的方式,繪制對應的路線,利用createPattern
繪制圓弧部分,利用canvas.arc
繪制直線部分,截取想要的内容,實作圓角矩形。canvas.lineTo
- 圖檔内容擷取。
`context.createPattern(imgUrl, "no-repeat")`
- 圓角矩形區域繪制

- 繪制内容

- 圖檔内容擷取。
- 文本自動換行:思路是通過
獲得目前文本寬度,每次添加一個字,比對此時文本寬度和行寬,超過時候繪制目前行,進行換行,y增加行高,重複這個過程。measureText
H5分享截圖方案優化
效果
- 實作了一套移動端截屏方法。解決了現有第三方庫html2canvas繪制清晰度低,圓弧計算精度低,深層DOM解析出錯的問題。
- 采用原子化實作方法。支援截屏自定義繪制,而不是如html2canvas和svg隻能通過複數次繪制不同DOM節點,來拼湊目标的方式。
總結
在網際網路時代,尤其是5G馬上要來臨的今天。傳統的分享模式,标題+單圖檔,逐漸難以滿足越來越豐富的活動宣傳要求。而流量的廉價化和短視訊火熱的時下,富圖文傳播無疑能傳遞更多的資訊。目前我們已經實作了基本DOM節點繪制方案,并在站内活動中使用富圖文分享。相信在不久的将來,我們能夠利用移動端截屏分享功能幫助更多閑魚使用者高效率分享内容,讓使用者樂在閑魚,玩在閑魚。