跳至內容
Astera Technology

中文組字確認鍵,不應同時送表單

先核所附組字標記,才把 Enter 當送出。

下載完整個案資料及參考答案 ↓

訂判斷及所需輸入

假設輸入是「中文」。首次 Enter 的 isComposing=true,用來確認候選字;第二次是 false,才可送出。逢 Enter 都送會提交兩次;更正後只送一次,完整文字仍保留。

已填本地測試工作表
情況輸入 JSON
原例測試{"text":"中文","enterCompositionFlags":[true,false]}
下載可編輯 CSV ↓

跑所附比較

把所附標記放進真正 DOM KeyboardEvent,實際試監聽器;未表示已試所有實體輸入法或作業系統。

錯誤及所需輸出
路徑輸出 JSON
錯誤路徑{"submissions":2,"finalText":"中文"}
所需路徑{"submissions":1,"finalText":"中文"}
下載可編輯 CSV ↓
Node24.14.1 程序;須 Playwright1.63 Chromium
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
const htmlEscape=s=>String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
async function withPage(action,options={}){
  const require=createRequire(import.meta.url);const {chromium}=require('playwright');
  const browser=await chromium.launch({headless:true});
  try{const context=await browser.newContext(options);const page=await context.newPage();
    const requests=[];await page.route('**/*',route=>{requests.push(route.request().url());return route.abort();});
    return await action(page,context,requests);
  }finally{await browser.close();}
}

const run=async function run(i,corrected=true){
    if(!i.enterCompositionFlags.every(v=>typeof v==='boolean'))return {held:true};
    return withPage(async page=>{await page.setContent('<label>Memo<input id="memo"></label><output id="count">0</output>');
      await page.evaluate(corrected=>{let count=0;document.querySelector('#memo').addEventListener('keydown',e=>{if(e.key==='Enter'&&(!corrected||!e.isComposing))document.querySelector('#count').textContent=String(++count);});},corrected);
      await page.fill('#memo',i.text);for(const composing of i.enterCompositionFlags)await page.dispatchEvent('#memo','keydown',{key:'Enter',isComposing:composing});
      return page.evaluate(()=>({submissions:Number(document.querySelector('#count').textContent),finalText:document.querySelector('#memo').value}));});
  };
const cases=[{"input":{"text":"中文","enterCompositionFlags":[true,false]},"corrected":false,"expected":{"submissions":2,"finalText":"中文"}},{"input":{"text":"中文","enterCompositionFlags":[true,false]},"corrected":true,"expected":{"submissions":1,"finalText":"中文"}},{"input":{"text":"你","enterCompositionFlags":[true]},"corrected":true,"expected":{"submissions":0,"finalText":"你"}},{"input":{"text":"Ada","enterCompositionFlags":[false]},"corrected":true,"expected":{"submissions":1,"finalText":"Ada"}}];
for(const test of cases){const actual=await run(test.input,test.corrected);assert.deepEqual(actual,test.expected);console.log(actual);}
下載可執行例子 ↓

按邊界依據作判斷

只有候選確認是零次;普通非組字 Enter 一次,欄內文字不清。

  1. 核組字標記
  2. 只放行所需送出事件
  3. 核次數及原文

確認候選字不等於提交。

可編輯邊界輸入及結果
條件輸入 JSON預期輸出 JSON
只確認候選字{"text":"你","enterCompositionFlags":[true]}{"submissions":0,"finalText":"你"}
普通 Enter{"text":"Ada","enterCompositionFlags":[false]}{"submissions":1,"finalText":"Ada"}
下載可編輯 CSV ↓

原例兩個事件,應送出幾次?

查看參考答案

一次,在非組字 Enter 後;確認候選字是另一個動作。

相關資源