體驗更優排版請移步原文:http://blog.kwin.wang/programming/emoji-transform-commit.html
之前就遇到過需要前端支持用戶輸入並提交emoji表情的問題,一直沒有着手解決,今天再一次狹路相逢,該來的躲不過,那就嘗試去解決吧。
大多數emoji表情都是4字節的utf-16編碼(為輔助平面字符,另有少部分表情屬於2字節的基本平面字符),而我們的MySQL數據庫采用utf-8,並且最大允許3字節的字符,因此前端提交由用戶輸入的4字節的emoji表情在存入數據庫時會報錯。在后台不動的情況下,有一種解決方案就是前端進行處理,將emoji表情轉換為字符實體再提交。

這是一張Unicode字符百科的截圖,前三個是2字節的基本平面字符,之后的是4字節的輔助平面字符,例如Grinning Face,
是它的utf-16的編碼,
就是它的字符實體,這一類也就是我們要進行處理的一類。
我們要將這一類emoji表情轉為字符實體存入數據庫,首先我們先要進行字符檢測,這里要用到正則表達式,由於JavaScript采用ucs-2編碼,所有字符在JavaScript中都是2字節,所以4字節的emoji表情會被當做兩個雙字節字符處理,這里有個高位(H)和低位(L)的概念(有興趣請閱讀阮一峰老師一篇文章),所以我們檢測4字節emoji表情的正則表達式應該是:/[\ud800-\udbff][\udc00-\udfff]/g。

阮老師文章中提到了utf-16轉ucs-2(unicode)的公式,我們需要進行反推來轉換成我們需要的ucs-2編碼。這里是資料Demo中的一個處理函數:
1 utf16toEntities: function(str) { //檢測utf16emoji表情 轉換為實體字符以供后台存儲 2 var patt=/[\ud800-\udbff][\udc00-\udfff]/g; 3 str = str.replace(patt, function(char){ 4 var H, L, code; 5 if (char.length===2) { //輔助平面字符(我們需要做處理的一類) 6 H = char.charCodeAt(0); // 取出高位 7 L = char.charCodeAt(1); // 取出低位 8 code = (H - 0xD800) * 0x400 + 0x10000 + L - 0xDC00; // 轉換算法 9 return "&#" + code + ";"; 10 } else { 11 return char; 12 } 13 }); 14 return str; 15 }
經過上述轉換,我們手機端輸入的emoji表情應該就可以提交到數據庫了,but...解決問題往往不會這么一帆風順,我們發現正常保存的emoji表情在頁面上不能正常顯示,我們前端采用angular開發,用{{}}將包含emoji字符實體的字符串渲染到頁面上時顯示的直接是這樣
的字符實體,審查元素發現HTML內容是這樣
,一時還不知道原因是什么,但一定是用{{}}渲染有問題,嘗試換用ng-bind-html,
1 <div class="bloodPressureRemarks text-left ellipsis" ng-bind-html="item.remarks"></div>
問題解決!
