赞
踩
前段时间被这样一个bug给折磨到,在ios手机端,切换中文输入法输入打拼音到input输入框的时候,发现打拼音的时候也会频繁触发input事件以至于输入框一直处于抖动状态,加上防抖截流也无济于事反而会让用户觉得特别的卡顿。
问题排查:
查看了源码,发现taro只是做了一层套娃,底层是react框架
写了个react的demo发现,react其实也有这样的问题
- const Demo=()=>{
- const [value,setValue]=useState("");
- return (
- <>
- <input onInput={(e)=>{
- console.log("value:",e.target.value)
- setValue(e.target.value)
- }}/>
- <span>{value}</span>
- </>
- )
- }
看过react的源码的人都会知道,react对于原生dom事件其实也是没有过多的去处理,于是我做了一下论证
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- </head>
- <body>
- <input type="text" >
- <script>
- const input=document.querySelector('input')
- input.addEventListener('input',function(e){
- console.log("e",e)
- })
- </script>
- </body>
- </html>
验证结果如下确实如此
那么接下来就轮到主角上场了
文本合成系统如 input method editor(即输入法编辑器)开始新的输入合成时会触发 compositionstart
事件。
例如,当用户使用拼音输入法开始输入汉字时,这个事件就会被触发。
当文本段落的组成完成或取消时,compositionend 事件将被触发 (具有特殊字符的触发,需要一系列键和其他输入,如语音识别或移动中的字词建议)。
于是我对react代码的input输入框添加了以上两方法
- const Demo = () => {
- const [value, setValue] = useState("");
- return (
- <>
- <input
- onCompositionStart={(e) => {
- console.log("onCompositionStart")
- }}
- onInput={(e) => {
- console.log("value:", e.target.value);
- setValue(e.target.value);
- }}
- />
- <span>{value}</span>
- </>
- );
- };
当切换到中文输入到时候 compositionstart事件触发了
当输入完成的时候compositionend触发了
当切换会英文输入的时候,就不会触发
于是乎对代码做了这样的改造:
- const Demo = () => {
- const [value, setValue] = useState("");
- return (
- <>
- <input
- onCompositionStart={(e) => {
- console.log("onCompositionStart")
- e.target.composing = true
- }}
- onCompositionEnd={(e) => {
- console.log("onCompositionEnd",e.target.value)
- if(!e.target.composing)return;
- (e.target.composing = false)
- setValue(e.target.value);
- }}
- onInput={(e) => {
- if(e.target.composing) return;
- console.log("value:", e.target.value);
- setValue(e.target.value);
- }}
- />
- <span>{value}</span>
- </>
- );
- };
也就完全解决了中文输入的时候输入框问题
- const directive = {
- inserted (el, binding, vnode, oldVnode) {
- if (vnode.tag === 'select') {
- // #6903
- if (oldVnode.elm && !oldVnode.elm._vOptions) {
- mergeVNodeHook(vnode, 'postpatch', () => {
- directive.componentUpdated(el, binding, vnode)
- })
- } else {
- setSelected(el, binding, vnode.context)
- }
- el._vOptions = [].map.call(el.options, getValue)
- } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
- el._vModifiers = binding.modifiers
- if (!binding.modifiers.lazy) {
- el.addEventListener('compositionstart', onCompositionStart)
- el.addEventListener('compositionend', onCompositionEnd)
- // Safari < 10.2 & UIWebView doesn't fire compositionend when
- // switching focus before confirming composition choice
- // this also fixes the issue where some browsers e.g. iOS Chrome
- // fires "change" instead of "input" on autocomplete.
- el.addEventListener('change', onCompositionEnd)
- /* istanbul ignore if */
- if (isIE9) {
- el.vmodel = true
- }
- }
- }
- },
- function onCompositionStart (e) {
- e.target.composing = true
- }
-
- function onCompositionEnd (e) {
- // prevent triggering an input event for no reason
- if (!e.target.composing) return
- e.target.composing = false
- trigger(e.target, 'input')
- }
-
- function trigger (el, type) {
- const e = document.createEvent('HTMLEvents')
- e.initEvent(type, true, true)
- el.dispatchEvent(e)
- }
由此看出鱿大大,在写vue框架的时候是多么细心,这些细节都考虑到了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。