中文輸入法搜尋:等 compositionend 再篩選
更新時間: 2026/10/26
Try the example
Open the demo in a new tab要解決的問題
用中文輸入法打字時,鍵入的注音或拼音還不是最後要搜尋的字。如果每次 input 都立刻篩選,選字期間列表可能先顯示「沒有結果」,或跳到不相關的項目。
上方範例有兩個欄位:左邊每次輸入都篩選,右邊等選字完成才篩選。可以用中文輸入法分別輸入「台灣」試試;沒有中文輸入法時,按「模擬選字過程」也能看到差異。在新分頁打開完整範例,用「檢視原始碼」查看可獨立執行的 HTML、CSS 和 JavaScript。
Vanilla JavaScript 的關鍵
compositionstart 表示開始組字;這段期間照常顯示使用者輸入的文字,但先不要改搜尋用的 query。compositionend 再用輸入框當下的值搜尋:
let isComposing = false;
let query = "";
input.addEventListener("compositionstart", () => {
isComposing = true;
});
input.addEventListener("input", (event) => {
if (!isComposing) search(event.currentTarget.value);
});
input.addEventListener("compositionend", (event) => {
isComposing = false;
search(event.currentTarget.value);
});
function search(value) {
query = value.trim().toLocaleLowerCase();
renderResults(query);
}
不要在 compositionend 只讀前一次的 state;直接取 event.currentTarget.value,才不會碰到更新時序問題。不同瀏覽器可能在 compositionend 前後各送一次 input,上面的處理可能重複搜尋同一個值;若搜尋會發網路請求,可在 search 裡比較新舊 query,避免重複請求。
React:顯示值和篩選值分開
在可搜尋的國碼選單中,input 是畫面上的字,query 才是用來篩選選項的字。組字期間只更新前者:
import { useRef, useState } from "react";
function SearchInput({ onQueryChange }) {
const [input, setInput] = useState("");
const isComposing = useRef(false);
return (
<input
value={input}
onChange={(event) => {
const next = event.currentTarget.value;
setInput(next);
if (!isComposing.current) onQueryChange(next);
}}
onCompositionStart={() => {
isComposing.current = true;
}}
onCompositionEnd={(event) => {
isComposing.current = false;
onQueryChange(event.currentTarget.value);
}}
aria-label="Search country"
/>
);
}
下次怎麼驗證
- 開始輸入注音或拼音、但還沒選字時,欄位文字會變;結果列表保持不動。
- 選字送出後,列表才依完整文字更新。
- 英文、貼上、刪除文字仍應立即篩選。
- 用測試事件送出
compositionStart→change→compositionEnd,確認中間結果數量不變,最後才更新。