input输入法输入
input 常用的有两个事件,input、change。
但是当用输入法输入中文的时候,会出现问题。
测试input、change事件测试
- 创建一个
input.html
文件,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<input id="my-input" type="text" />
<script>
var input = document.querySelector('#my-input')
input.addEventListener('input', function(e) {
console.log('input event:', e.target.value)
})
input.addEventListener('change', function(e) {
console.log('change event:', e.target.value)
})
</script>
</body>
</html>
-
在浏览器中打开,并在输入框中输入一些内容:
下图是在input输入框中输入 123 ,然后失去焦点后的效果
-
于是有这样的结论:
input事件是:当输入框中的内容改变时触发。
change事件是:当输入框的内容改变后并失去焦点后触发。
input事件的局限(输入法输入中文等)
当使用输入法输入中文时,input事件会对还没有“确定过的内容”触发input事件。如下图:
有时候这会给我们造成一些困扰。
现在我们对input.html
做一些改变
<input id="my-input" type="text" />
<script>
var input = document.querySelector('#my-input')
input.addEventListener('input', function(e) {
console.log('input event:', e.target.value)
+ setInput(e.target.value)
})
input.addEventListener('change', function(e) {
console.log('change event:', e.target.value)
})
+ function setInput(value) {
+ input.value = value.slice(0, 4)
+ }
</script>
我们希望对input输入框中的长度进行限制(不能超过4位)。
此时我们再也无法输入“你好”的中文,唯一的办法就是通过复制粘贴或是输入法的联想功能。
这时候input事件无法满足对输入内容做限制的需求了。
compositionstart 和 compositionend
当我们是用输入法输入的时候,文本还没确定。
在输入框中的体现为,输入框的文本下面有一条线:
我们再次修改input.html
<input id="my-input" type="text" />
<script>
var input = document.querySelector('#my-input')
input.addEventListener('input', function(e) {
console.log('input event:', e.target.value)
setInput(e.target.value)
})
input.addEventListener('change', function(e) {
console.log('change event:', e.target.value)
})
+ input.addEventListener('compositionstart', function(e) {
+ console.log('compositionstart event:', e.target.value)
+ })
+ input.addEventListener('compositionend', function(e) {
+ console.log('compositionend event:', e.target.value)
+ })
function setInput(value) {
input.value = value.slice(0, 4)
}
</script>
我们尝试输入 "你"(拼音“ni”):
可以发现 事件触发的顺序是 compositionstart -> input -> compositionend -> change
compositionstart 只会在 文本输入存在不确定的情况下 才会触发
compositionend 在 文本输入不确定的值变为确定的值 才会触发
这样我们就可以利用compositionend事件来对input输入框进行限制。
我们改写一下input.html
:
<input id="my-input" type="text" />
<script>
var input = document.querySelector('#my-input')
input.addEventListener('input', function(e) {
console.log('input event:', e.target.value)
+ // setInput(e.target.value)
})
input.addEventListener('change', function(e) {
console.log('change event:', e.target.value)
})
input.addEventListener('compositionstart', function(e) {
console.log('compositionstart event:', e.target.value)
})
input.addEventListener('compositionend', function(e) {
console.log('compositionend event:', e.target.value)
+ setInput(e.target.value)
})
function setInput(value) {
input.value = value.slice(0, 4)
}
</script>
现在我们尝试输入一个超过4个字的汉字:
然后选中第一个候选项
现在我们成功的对输入框进行了限制。
问题解决了吗?
当我们输入非中文字符的时候:
会发现compositionend事件并没有触发。
更好的办法
现在我们知道了,compositionend事件触发的前提是 不确定字符转为确定字符。
所以,我们需要做的就是当用户输入的是 不确定字符 的时候(例如用中文输入法)用 compositionend事件来限制input输入框的值;
当用户输入的是 确定字符 的时候 ,用input事件来限制。
那么我们怎么知道用户输入的是 确定字符 还是 不确定字符 呢?
这时,compositionstart派上用场了,当compositionstart事件触发就标志这次输入是 不确定字符 ;当compositionend事件触发标志 不确定字符 输入过程结束。
我们可以声明一个isComposing
变量来表示当前输入是哪种场景。
改写input.html
:
<input id="my-input" type="text" />
<script>
var input = document.querySelector('#my-input')
+ var isComposing = false
input.addEventListener('input', function(e) {
+ if (isComposing) return
console.log('input event:', e.target.value)
+ setInput(e.target.value)
})
input.addEventListener('change', function(e) {
console.log('change event:', e.target.value)
})
input.addEventListener('compositionstart', function(e) {
+ isComposing = true
console.log('compositionstart event:', e.target.value)
})
input.addEventListener('compositionend', function(e) {
+ isComposing = false
console.log('compositionend event:', e.target.value)
setInput(e.target.value)
})
function setInput(value) {
input.value = value.slice(0, 4)
}
</script>
这样一来,我们就可以完美的解决 输入框限制的需求。