支持英文/漢字/emoji長度計算的輸入框?qū)崿F(xiàn)
幕思城_北辰樓主|2022-10-27|17:07|發(fā)布在分類 / 淘寶規(guī)則|閱讀:76
幕思城_北辰樓主|2022-10-27|17:07|發(fā)布在分類 / 淘寶規(guī)則|閱讀:76
后臺用戶輸入是平臺獲取用戶信息的重要途徑,也是用戶自我表達的重要方式,尤其是在社區(qū)商業(yè)場景下。
輸入過程的流暢性、準確性和豐富性是我們要保證的重點。
下圖是近期的產(chǎn)品需求。
在“圈內(nèi)好物”部分下,允許用戶定義“商品分組”。
產(chǎn)品與設計專業(yè)的學生有兩個核心訴求:明確的任務目標:對于輸入的字數(shù)限制,首先想到的是原生maxlength參數(shù)。
的傳統(tǒng)maxlength參數(shù)控制輸入框的最大輸入長度。
在限制輸入字符的同時,還具有良好的交互體驗,可以截斷超過長度的輸入內(nèi)容。
但是maxlength不出所料,分不清中英文字符的長度。
再次嘗試表情符號。
看了MDN文檔。
原來maxlength限制了字符串的編碼長度。
要解釋上面的問題,我們先來了解一下Unicode的字符點。
在Unicode中,字符由U+_hhhhhh _六位十六進制小數(shù)點表示。
Unicode也把連續(xù)的65,536個字符點作為一個字符平面,比如U U+000000-U+00FFFF作為平面0。
而我們常用的中英文文本字符就編碼在這個區(qū)域。
Javascript字符串以UTF-16編碼,由一系列16位字節(jié)組成。
這里可以注意到,常用的字符(U U+000000-U+00FFFF)都可以用一個16位字節(jié)來表示。
這就解釋了為什么在傳統(tǒng)的maxlength計算中,漢字和英文的編碼長度是一樣的。
對于常用字符,Unicode定義了便于區(qū)分的部分。
比如字符點的范圍U+4E00-U+9FFF是CJK統(tǒng)一表意文字,我們可以根據(jù)字符點的范圍直接計算長度。
表情符號編碼比較特殊。
表情符號存在于平面1(U+010000-U+01FFFF),所以不能直接用一個字符點來表示。
在UTF-16編碼中,表情符號由代理對編碼。
比如Unicode代碼是U+1F600,在Javascript代碼中是由0xD83D 0xDE00組成的。
對于字符串處理,人們通常會想到使用charCodeAt()。
但是charCodeAt()獲取的是index對應的UTF-16碼,所以無法獲取的碼位碼。
幸運的是,Javascript提供了codePointAt(),它可以識別代理對并獲得正確的代碼。
如果用codePointAt(),好像就能分辨表情符號了吧?。
上圖所示的國旗和家庭表情符號屬于組合表情符號(復合表情符號)。
與普通表情符號不同的是,組合表情符號的編碼更加復雜,第一次學習這個我感到非常驚訝。
編碼方法涉及特殊字符U+200D,也稱為零寬度Joiner,ZWJ),以及表情符號修飾符(Emoji Modifier)。
下面舉幾個例子:在這樣“混亂”的環(huán)境下,有什么通用的解決方法嗎?在網(wǎng)上搜了一下,最后用社區(qū)里比較成熟的表情符號regex來識別表情符號。
最后總結(jié)長度計算的解決方法:3。
求和并計算文本的總長度。
處理文本的自動截斷完成了字符串的長度計算,然后我們要解決自動截斷的問題。
當用戶輸入超過限制長度的文本時,我需要自動截斷。
經(jīng)過多次參照maxlength的交互處理,我列舉了以下兩種情況:OnInput提供的inputEvent包含一個inputType類型,用來區(qū)分不同的輸入事件。
我可以根據(jù)事件類型處理各種情況嗎?但實際調(diào)查表明,inputType的類型遠比想象的復雜,所有處理的成本都非常大。
復雜性是一個問題,不同瀏覽器容器環(huán)境的兼容性是另一個問題。
比如在閑魚的android webView中,因為不支持insertReplacementText事件,所以所有的insertReplacementText事件都會被insertText事件替換,這是一個很頭疼的問題。
粘貼,這種情況下只會觸發(fā)insertText事件,無法獲取刪除的文本" _ width = " 677 px " src = "/202208/24/16613461682159570 . jpg & wx from = 5 & wx _ lazy = 1 & wx _ co = 1 " cross origin = " anonymous " alt = padding:0px;大綱:0px最大寬度:100%;垂直對齊:底部;行高:1.75;邊框-半徑:4px顯示:塊;框尺寸:邊框-框!重要;溢出-換行:斷字!重要;身高:自動!重要;寬度:677px!重要;能見度:可見!重要;”>所以又回到了那個問題:有沒有一個通用的解決方案?既然inputType不可靠,我們能不能直接處理oninput事件的更新文本(值)?作為基本事件,至少兼容性沒有問題。
這里的方案是獲取oninput事件的值,然后用上次的舊文本做一個Diff,最后根據(jù)Diff的結(jié)果進行處理。
在Diff計算中,我們考慮三種情況:最后,構造Diff結(jié)果。
如果用戶輸入的總長度大于指定長度,那么我們可以基于insertChunk截取它。
這樣可以在一定程度上減輕對inputType的依賴。
但是還有幾個問題需要提一下。
3.1 IOS拼音輸入在maxlength的截斷交互中,用戶輸入漢語拼音結(jié)合中文(排版)時沒有限制。
在用戶完成拼音到中文組合的輸入后,根據(jù)組合的文本長度對其進行截斷。
在IOS下,輸入組件提供compositionend的監(jiān)聽事件。
當用戶輸入拼音時,inputEvent的inputType事件的名稱是insertCompositionText。
所以當用戶輸入時,我們可以先忽略這個事件,然后在compositionend事件被觸發(fā)時處理文本。
3.2事件之上的其他不兼容解決方案已經(jīng)可以支持大部分用戶輸入交互。
但是,仍然有一些不兼容的事件,比如撤銷/重做。
這些事件將在截斷前恢復原始文本,并與截斷邏輯沖突。
考慮到移動用戶不常使用撤銷/重做等操作,這里可以屏蔽撤銷/重做事件。
掩碼回調(diào)在beforeinput事件中處理,您可以使用preventDefault()來阻止下一個輸入事件。
因為還有很多類型的inputType事件,所以我們這次沒有全部測試。
如果以后遇到一些不兼容的事件,也可以考慮直接屏蔽,保證基本的輸入功能,不影響用戶交互。
Demo & code片段文本長度計算代碼這里不具體給出,一般邏輯如下 文本比較代碼:這里提供了文本比較的代碼。
這里的比較邏輯比較簡單,因為處理用戶輸入,比較結(jié)果必須是(1)整塊插入,(2)整塊刪除,(3)整塊替換中的一個。
在對輸入的事件處理的總結(jié)的道路上,有許多曲折。
最后終于做出了滿意的組件。
在這個過程中,我了解了Javascript字符串和Unicode編碼,尤其是emoji編碼,真的很有趣。
這個輸入框的方案也解決了一個困擾前端輸入框的難題,希望能給大家?guī)硪恍﹩l(fā)。
reference https://www . Unicode . org/reports/tr11/https://en . Wikipedia . org/wiki/Plane _(Unicode)# Supplementary _ Multilingual _ Plane https://thekevinscott.com/emojis-in-javascript/ https://en . Wikipedia . org/wiki/CJK _統(tǒng)一_表意文字_(Unicode_block)
這個問題還有疑問的話,可以加幕.思.城火星老師免費咨詢,微V.信X號是為: msc496。
微信掃碼回復「666」