input输入法输入

input 常用的有两个事件,input、change。
但是当用输入法输入中文的时候,会出现问题。

测试input、change事件测试

  1. 创建一个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>
  1. 在浏览器中打开,并在输入框中输入一些内容:
    下图是在input输入框中输入 123 ,然后失去焦点后的效果

  2. 于是有这样的结论:
    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事件无法满足对输入内容做限制的需求了。

compositionstartcompositionend

当我们是用输入法输入的时候,文本还没确定。
在输入框中的体现为,输入框的文本下面有一条线:

我们再次修改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>

这样一来,我们就可以完美的解决 输入框限制的需求。

posted @ 2020-01-09 12:00  菜鸡_chicken  阅读(593)  评论(0编辑  收藏  举报