亚洲乱色熟女一区二区三区丝袜,天堂√中文最新版在线,亚洲精品乱码久久久久久蜜桃图片,香蕉久久久久久av成人,欧美丰满熟妇bbb久久久

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

中文輸入法在前端中的監(jiān)聽(tīng)問(wèn)題

freeflydom
2025年11月6日 10:24 本文熱度 430
?(原標(biāo)題:被中文輸入法坑死了)

PM:在PC端做一個(gè)@功能吧,就是那種...。

我:你不用解釋??我知道那個(gè)功能,監(jiān)聽(tīng)keydown事件,然后e.keycode === 50,那可太簡(jiǎn)單了。

那可太簡(jiǎn)單了,可太簡(jiǎn)單了,太簡(jiǎn)單了,簡(jiǎn)單了,單了,了......(掉進(jìn)坑里的回聲)

坑1:KeyBoardEvent.keycode

 廢棄的屬性你就堅(jiān)持用吧,一用一個(gè)不吱聲。以后線上跑得好好的代碼突然報(bào)錯(cuò)了,你都不知道bug在哪兒。

現(xiàn)在的web標(biāo)準(zhǔn)里,要確定一個(gè)鍵盤(pán)事件是靠e.keye.code。code代表觸發(fā)事件的物理按鍵,比如2的位置code='Digit2'。key返回用戶按下的物理按鍵的值,它還與 shiftKey 等調(diào)節(jié)性按鍵的狀態(tài)、鍵盤(pán)的區(qū)域和布局有關(guān)。

所以對(duì)于@來(lái)說(shuō),直接判斷e.key === "@"來(lái)做后續(xù)的操作就行了。

addEventListner('keydown', (e) => {
  if (e.key === "@") {
    e.preventDefalut(); // 這里去掉@字符是為了后續(xù)插入和監(jiān)聽(tīng)方便處理
    // 插入有@字符的,可監(jiān)聽(tīng)輸入的元素
    // 喚起小窗....
  }
});

仔細(xì)看上面的這幾行代碼和注釋?zhuān)_(kāi)始考(坑)了。

坑2:輸入法的坑

起因

在我美滋滋地以為避過(guò)了坑1就沒(méi)事了的時(shí)候,一個(gè)夜晚我的測(cè)試同學(xué)告訴我,在測(cè)試環(huán)境突然就體驗(yàn)不到這個(gè)功能了,無(wú)論輸入多少個(gè)@都不行,白天還好好的??。

好一個(gè)「白天還好好的」。

我自己測(cè)試的時(shí)候又百分百能體驗(yàn)到??,所以最開(kāi)始我還在懷疑他沒(méi)有配上測(cè)試系統(tǒng)......

于是,讓測(cè)試同學(xué)的windows電腦連到我的開(kāi)發(fā)環(huán)境debug一看:

好家伙,真是好家伙??他的電腦的e.key === "Process"????!!!

什么意思呢,就是正常我們理想中的@字符產(chǎn)生是shift+2按鍵的組合,監(jiān)聽(tīng)keydown之后我們會(huì)按順序收到兩個(gè)回調(diào):

  1. e.key === "Shift",e.code === "ShiftLeft"或者shiftRight
  2. e.key === "@"e.code === "Digit2"

但是實(shí)際在測(cè)試同學(xué)的電腦里,1是一樣的,但是2變了,2變成了e.key === "Process"。

雖然鍵盤(pán)事件有變化,但是在前端頁(yè)面上的@字符是沒(méi)有任何變化的。難怪他說(shuō)他會(huì)突然失效了。我問(wèn)他做了什么怎么會(huì)突然變了,他想了想說(shuō)晚上從系統(tǒng)輸入法換成了微信輸入法.....

上網(wǎng)檢索(chatGPT)了一番,明白了一個(gè)新的知識(shí)點(diǎn):

輸入法的全稱叫Input Method Editor輸入法編輯器(IME)。本質(zhì)上它也是個(gè)編輯器。為了能輸入各類(lèi)字符(比如漢字和阿拉伯字等),IME會(huì)先處理用戶的英文字母輸入然后通過(guò)系統(tǒng)的底層調(diào)用傳遞給瀏覽器,瀏覽器再顯示到用戶的界面。這里的Process很大概率就是當(dāng)時(shí)輸入法給出的某個(gè)值表示那個(gè)時(shí)刻它還在處理中。

解決辦法

既然KeyBoardEvent靠不住,那我們換一種監(jiān)聽(tīng)方式。

我找到了一個(gè)非常適用于輸入法的監(jiān)聽(tīng)事件叫做CompositionEvent,它表示用戶間接輸入文本(如使用輸入法)時(shí)發(fā)生的事件。此接口的常用事件有compositionstartcompositionupdate 和 compositionend。它們?nèi)齻€(gè)事件分別對(duì)應(yīng)的動(dòng)作,通俗一點(diǎn)說(shuō)就是你用輸入法開(kāi)始打字、正在打字和結(jié)束打字。

于是乎,我監(jiān)聽(tīng)compositionend不就行了!在輸入法end的時(shí)候我再去看你end的字符是不是@不就行了!

// addEventListner('keydown', (e) => {
addEventListner('compositionend', (e) => {
  // if (e.key === "@") {
  if (e.data === "@") {
    e.preventDefalut(); // 這里去掉@字符是為了后續(xù)插入和監(jiān)聽(tīng)方便處理
    // 插入有@字符并且可監(jiān)聽(tīng)輸入的元素
    // 喚起小窗....
  }
});

對(duì)于輸入法來(lái)說(shuō),按鍵的up和down的key值就算不盡人意也沒(méi)什么損失,畢竟用戶毫無(wú)感知。但是,compositionend永遠(yuǎn)是不會(huì)錯(cuò)的,如果compositionende.data都不是@字符了,那么在用戶的編輯器界面上的顯示肯定也會(huì)跟著出錯(cuò)。

所以監(jiān)聽(tīng)這個(gè)肯定就是萬(wàn)無(wú)一失的方法了,哈哈哈我真是個(gè)“天才”(蠢材)。 修改之后讓測(cè)試同學(xué)嘗試之后果然就可以了。

坑3:輸入法繼續(xù)坑

起因

時(shí)間過(guò)去了沒(méi)一會(huì),本天才就收到了另一個(gè)測(cè)試同學(xué)反饋的問(wèn)題說(shuō)為什么輸入了一個(gè)@字符之后,會(huì)出現(xiàn)兩個(gè)@在界面上?

我第一反應(yīng)就是難道沒(méi)有執(zhí)行到e.preventDefalut()?既然后續(xù)功能能正常使用,沒(méi)執(zhí)行到也不應(yīng)該啊??。然后在我電腦一通嘗試,發(fā)現(xiàn)safari瀏覽器在輸入法為中文的情況下也會(huì)觸發(fā)這個(gè)問(wèn)題。

于是,讓測(cè)試同學(xué)的windows電腦連到我的開(kāi)發(fā)環(huán)境debug一看(梅開(kāi)二度):

執(zhí)行到了,也沒(méi)有報(bào)錯(cuò)什么的,但是@字符并沒(méi)有被prevent掉??。

再加上我自己傳入的@,所以界面上就出現(xiàn)了兩個(gè)@字符。啊這這這,這很難評(píng)......

我是左思右想,百思不得其解,于是只能:

 stack overflow上也有這個(gè)問(wèn)題。

上面大概的意思就是compositionend事件里使用 e.preventDefault() 在技術(shù)上可行的,但它可能不會(huì)產(chǎn)生你期望的效果??赡苁且?yàn)?code style="font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.87em; word-break: break-word; border-radius: 2px; overflow-x: auto; background-color: rgb(255, 245, 245); color: rgb(255, 80, 44); padding: 0.065em 0.4em;"> compositionend 事件標(biāo)志著一次輸入構(gòu)成(composition)會(huì)話的結(jié)束,而在這個(gè)點(diǎn)上阻止默認(rèn)行為可能沒(méi)有意義,因?yàn)檩斎氲牧鞒桃呀?jīng)完成了。

更推薦用keydown,compositionstartinput來(lái)處理這種情況。

keydown是不可能keydown了,已經(jīng)被坑了。compositionstart也不行,因?yàn)閯傞_(kāi)始輸入那會(huì)才按下了shift鍵,@字符還沒(méi)出來(lái)呢。那就只能input了。

解決辦法

最開(kāi)始我沒(méi)有選擇input就是因?yàn)樗荒苁褂?code style="font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.87em; word-break: break-word; border-radius: 2px; overflow-x: auto; background-color: rgb(255, 245, 245); color: rgb(255, 80, 44); padding: 0.065em 0.4em;">e.preventDefault()。我必須要對(duì)輸入的字符串進(jìn)行單獨(dú)處理,去掉@,當(dāng)時(shí)覺(jué)得很麻煩就沒(méi)有選擇這個(gè)方法。

額....好好好,行行行,現(xiàn)在還是必須得處理一下了。

// addEventListner('keydown', (e) => {
// addEventListner('compositionend', (e) => {
addEventListner('input', (e) => {
  // if (e.key === "@") {
   if (e.data === "@") {
    ?怎么去處理字符呢 // 這里去掉@字符是為了后續(xù)插入和監(jiān)聽(tīng)方便處理
    // 插入有@字符并且可監(jiān)聽(tīng)輸入的元素
    // 喚起小窗....
  }
});

對(duì)于這個(gè)處理字符的方法,也是一個(gè)新知識(shí)點(diǎn)了。起初我還想的是去處理編輯器里的content,然后再給它插入回去,這樣子復(fù)雜度很高并且出錯(cuò)的概率極大。

這里的解決辦法主要是使用CharacterData接口?。CharacterData 接口是操作那些包含字符數(shù)據(jù)的節(jié)點(diǎn)的核心,特別是在需要?jiǎng)討B(tài)地更改文本內(nèi)容時(shí)。

例如,在一個(gè)文本節(jié)點(diǎn)上使用 deleteData() 方法可以從文本中移除一部分內(nèi)容,而不必完全替換或重寫(xiě)整個(gè)節(jié)點(diǎn)。

const selection = window.getSelection();
const { anchorNode, anchorOffset } = selection;
if (anchorNode.substringData(anchorOffset - 1, 1) === '@') {
  selection.anchorNode.deleteData(anchorOffset - 1, 1);
}

寫(xiě)完這個(gè)之后,我用自己的safari瀏覽器測(cè)試發(fā)現(xiàn)果然沒(méi)有問(wèn)題了。

哈哈哈我真是個(gè)“天才”(蠢材)。

坑4:輸入法深坑???

我自信滿滿地讓測(cè)試同學(xué)再重試一下??,然后測(cè)試同學(xué)說(shuō):和之前一樣啊,還是有兩個(gè)@字符。

我:???啊啊??啊啊?????

于是,讓測(cè)試同學(xué)的windows電腦連到我的開(kāi)發(fā)環(huán)境debug一看(梅開(kāi)三度):

發(fā)現(xiàn)測(cè)試同學(xué)電腦上的anchorOffset和正常的情況下是不一樣的,會(huì)小一位,所以導(dǎo)致anchorOffset - 1拿到的前一個(gè)字符并不等于@,所以后續(xù)也沒(méi)有把它處理掉??。

我是左思右想,百思不得其解,stack overflow上也沒(méi)有相關(guān)的問(wèn)題。不過(guò),結(jié)合IME的概念,肯定還是輸入法的問(wèn)題。

結(jié)合之前keydown的e.key==="Processing",可能在input觸發(fā)時(shí)輸入法的編輯器其實(shí)還是沒(méi)有完成工作(composition),導(dǎo)致在那個(gè)時(shí)候SelectionanchorOffset不一致。其實(shí)瀏覽器的Selection肯定不會(huì)錯(cuò),那anchorOffset看起來(lái)像是錯(cuò)了,我覺(jué)得應(yīng)該是輸入法在轉(zhuǎn)換的過(guò)程對(duì)我們的前端頁(yè)面做了一些用戶看不到的東西,而anchorOffset把它顯化出來(lái)罷了。

解決辦法

于是乎,我嘗試性的對(duì)處理字符串的那串代碼進(jìn)行延時(shí),目的是為了等待輸入法徹底工作完畢。

// addEventListner('keydown', (e) => {
// addEventListner('compositionend', (e) => {
addEventListner('input', (e) => {
  // if (e.key === "@") {
   if (e.data === "@") {
     setTimeout(() => {
       const selection = window.getSelection();
       const { anchorNode, anchorOffset } = selection;
       if (anchorNode.substringData(anchorOffset - 1, 1) === '@') {
         selection.anchorNode.deleteData(anchorOffset - 1, 1);
       } // 這里去掉@字符是為了后續(xù)插入和監(jiān)聽(tīng)方便處理
     });
   
    // 插入有@字符并且可監(jiān)聽(tīng)輸入的元素
    // 喚起小窗....
  }
});

然后,問(wèn)題真的就徹底解決了。

這個(gè)功能做起來(lái)可太簡(jiǎn)單了......??

轉(zhuǎn)自https://juejin.cn/post/7307041255740981286


該文章在 2025/11/6 10:26:10 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專(zhuān)業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車(chē)隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類(lèi)企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷(xiāo)售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved