.

本文轉自https://zhuanlan.zhihu.com/p/26141351餓了麼大神文章節選

在 Web 開發中,經常要對錶單元素的輸入進行限制,比如說不允許輸入特殊字元,標點。通常我們會監聽 input 事件:

inputElement.addEventListener('input', function(event) {
  let regex = /[^1-9a-zA-Z]/g;
  event.target.value = event.target.value.replace(regex, '');
  event.returnValue = false
});

這段程式碼在 Android 上是沒有問題的,但是在 iOS 中,input 事件會截斷非直接輸入,什麼是非直接輸入呢,在我們輸入漢字的時候,比如說「喜茶」,中間過程中會輸入拼音,每次輸入一個字母都會觸發 input 事件,然而在沒有點選候選字或者點選「選定」按鈕前,都屬於非直接輸入。

這顯然不是我們想要的結果,我們希望在直接輸入之後才觸發 input 事件,這就需要引出我要說的兩個事件—— compositionstart compositionend

compositionstart 事件在使用者開始進行非直接輸入的時候觸發,而在非直接輸入結束,也即使用者點選候選詞或者點選「選定」按鈕之後,會觸發 compositionend 事件。

var inputLock = false;
function do(inputElement) {
    var regex = /[^1-9a-zA-Z]/g;
    inputElement.value = inputElement.value.replace(regex, '');
}

inputElement.addEventListener('compositionstart', function() {
  inputLock = true;
});


inputElement.addEventListener('compositionend', function(event) {
  inputLock = false;
  do(event.target);
})


inputElement.addEventListener('input', function(event) {
  if (!inputLock) {
    do(event.target);
    event.returnValue = false;
  }
});

新增一個 inputLock 變數,當用戶未完成直接輸入前,inputLock 為 true,不觸發 input 事件中的邏輯,當用戶完成有效輸入之後,inputLock 設定為 false,觸發 input 事件的邏輯。這裡需要注意的一點是,compositionend 事件是在 input 事件後觸發的,所以在 compositionend事件觸發時,也要呼叫 input