监听输入框的输入,最原始的方法是使用keyup事件。
不使用change事件,它只会在输入框失去焦点后被触发。
此方式兼容性广,但效率较低,毕竟任意的按键都会触发该事件。浏览器
<input id="input" type="text" /> <script> document.querySelector('#input') .addEventListener('keyup', function() { console.log('value:', this.value); }); </script>
咱们只但愿当值发生变化后再触发监听,这样,input事件出现了。
它只会在输入框的值发生变化后被触发,不过IE8及如下不支持该事件。app
网上不少人使用IE独有的propertychange事件,做为替代input的方案,这里不推荐。
一方面它会在任意属性值变化后被触发,没有专注性,不够语义,比较浪费。
二方面网上都是用jQuery等工具库操做,比较简单,而咱们的目的是用原生代码实现。
三方面是不支持input事件的浏览器已经不多了,硬碰上了就用keyup对付。dom
<input id="input" type="text" /> <script> document.querySelector('#input') .addEventListener('input', function() { console.log('value:', this.value); }); </script>
接着上步,如何在不支持input事件时使用keyup事件呢?
直接检测事件不太靠谱,能够利用input在keyup以前发生的性质,巧妙的实现此功能。函数
<input id="input" type="text" /> <script> let inInputEvent = false; let input = document.querySelector('#input'); input.addEventListener('keyup', function() { if (inInputEvent) { // You can remove keyup listener. } else { console.log('keyup:', this.value); } }); input.addEventListener('input', function() { if (!inInputEvent) inInputEvent = true; console.log('input:', this.value); }); </script>
在搜索功能中,理想化的情景是当用户所有输入后,再当即执行搜索。
那么问题来了,如何在不须要用户点击搜索按钮的状况下,得知其过程的完成呢?没有办法。
虽然没有办法,但有优化的方式:假定用户每一个单词的输入间隔,以此时间延迟执行搜索功能。工具
英文通常为 300ms ,中文可设置成 500ms 。 <input id="input" type="text" /> <script> let input = document.querySelector('#input'); let trigger = createDelayFunction(console.log); input.addEventListener('input', function() { trigger(this.value); }); function createDelayFunction(fn, timeout = 300) { let timeoutId = -1; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => { fn.apply(null, args); }, timeout); } } </script>
中文、日文等须要借助输入法组合输入,即使是英文,如今也可借助组合输入进行选词等。
实际中,咱们但愿将用户组合输入完的一段文字,而不是每输入一个字母,算作一次输入的完成。优化
组合输入事件应运而生,经常使用的是compositionstart(组输开始)和compositionend(组输结束)事件。
结合组合事件不监听普通的输入,以及compositionstart发生在input事件以前,能够如此优化中文输入this
<input id="input" type="text" /> <script> let inCompositionEvent = false; let input = document.querySelector('#input'); input.addEventListener('input', function() { !inCompositionEvent && console.log('input', this.value); }); input.addEventListener('compositionstart', function() { inCompositionEvent = true; }); input.addEventListener('compositionend', function() { inCompositionEvent = false; console.log('composition', this.value); }); </script>
最后是结合以上几步生成一个融合方法,代码加示例:code
里面还作了些加强:
好比监听函数返回的是一个,移除这一步所加的全部事件的方法。
好比配置是否监听组合输入事件,由于好的搜索框会直接根据拼音开始搜索,无需等到汉字的造成。事件
代码使用ES6语法,需使用支持ES6的浏览器(Chrome最新版)或转码后才能使用,谅解ip
function listenInput(dom, callback, { timeout = 300, useCompositionEvent = true } = {}) { let value = ''; let inInputEvent = false; let inCompositionEvent = false; let trigger = createDelayFunction(valueChanged, timeout); // Return a function that can remove listeners added here. return enabledEvent(dom); function valueChanged(val) { if (val === value) { return ; } else { value = val; } callback(value, { dom: dom }); } function enabledEvent(dom) { dom.addEventListener('keyup', keyup); dom.addEventListener('input', input); useCompositionEvent && dom.addEventListener('compositionstart', compositionstart); useCompositionEvent && dom.addEventListener('compositionend', compositionend); return function() { dom.removeEventListener('keyup', keyup); dom.removeEventListener('input', input); useCompositionEvent && dom.removeEventListener('compositionstart', compositionstart); useCompositionEvent && dom.removeEventListener('compositionend', compositionend); }; function keyup() { if (inInputEvent) { dom.removeEventListener('keyup', keyup); } else { trigger(this.value); } } function input() { if (!inInputEvent) inInputEvent = true; if (!inCompositionEvent) trigger(this.value); } function compositionstart() { inCompositionEvent = true; } function compositionend() { inCompositionEvent = false; trigger(this.value); } } } function createDelayFunction(fn, timeout = 300) { let timeoutId = -1; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => { fn.apply(null, args); }, timeout); } }