天天看点

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

作者:格子衬衫

有个挺常见的需求相信大家应该都遇到过,就是一个搜索框,边输入边提示,类似于下面这样:

这玩意在前端也挺好实现的,就 v-model 然后 watch 再做个防抖请求接口呗!于是我

<template>
  <input v-model="value">
</template>

<script setup>
import { ref, watch } from 'vue';

const value = ref('')
watch(value, value => 请求接口(value))
</script>
           

这里先省略掉防抖,因为希望代码看起来更简洁、更让人专注 bug 所在位置、减少干扰,大家能明白意思就行。为了更好的向大家展示这个 bug 我们把请求接口换成更加经典的 console.log,每打印一次就代表请求了一次接口:

<template>
  <input v-model="value">
</template>

<script setup>
import { ref, watch } from 'vue';

const value = ref('')
watch(value, value => console.log(value))
</script>
           

只要输入框里的值发生变化了,那么就会请求接口,就会像下面这样:

我们想搜索黑粉,结果刚打出第一个字母就已经开始替我们搜索了,随着字符越输越多,黑粉也慢慢呈现在了我们的面前。

中文输入法

但就在产品走查的时候,她们用中文输入法输入的时候却发现没有随着字符的输入而进行搜索:

可以看到我们输入了这么多字符,但控制台从始至终都没打印过,证明了根本就没有监听到输入框里的变化。刚开始的时候我还狡辩呢,说什么像这种带着下划线的代表没输入完不会进入到输入里,所以输入框检测不到任何字符:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

她听完后半信半疑的走了,而我自己则是全信了,因为我以为事实就是这样。但过了一会她又回来了:你看百度谷歌它们的中文输入法都是没问题的啊:

这下轮到我尴尬了:她会不会以为刚刚是我找了个蹩脚的理由敷衍她,但实际上我真这么认为的,因为我看了半天代码也没看出来哪写的不对,但她用事实告诉我这就是我的 bug。想了半天也没想出个所以然来,后来琢磨会不会是 Vue 的 bug?因为无论百度谷歌还是必应它们都没用 Vue,所以它们没这个 bug,于是我用原生 JS 试了一下:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

看来果然是 Vue 的锅,然后我赶忙跟她解释说这是 Vue 的 bug,她一脸鄙视:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?
你都赖多少次 Vue 了,是不是只要一有 bug 就都甩到 Vue 身上? 人家 Vue 好歹也是三大框架之一,不至于这么 Low 吧?一个带输入法的输入框都不支持?

我:这是真的啊,不过也不是不能解决,这次我把原生的写法写到 Vue 里去:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

结果居然是好的:

接下来我陷入了短暂的沉思:原来的代码在刨除掉业务部分后在 <input> 上仅仅只用了 v-model 这一个属性,难道是 v-model 的问题?为了验证我的猜想我把原先的 v-model 给改成了 :value + @input:

<template>
  <input :value="value" @input="value = $event.target.value">
</template>

<script setup>
import { ref, watch } from 'vue';

const value = ref('')
watch(value, value => console.log(value))
</script>
           

这直接惊掉了我的下巴,因为在我印象中 v-model 就是 :value + @input 的语法糖,它俩是全等的关系:

<input v-model="value"> === <input :value="value" @input="value = $event.target.value">           

因为 Vue 官网里就是这么写的:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

但为什么它们俩的行为不一致呢?而且为什么 v-model 会在中文输入法的情况下出 bug 呢?这些问题我们只能从源码里来找答案了。

源码

源码版本 3.3.4,在 packages 里的 runtime-dom 下的 src 内的 directives 中有个 vModel.ts:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

在第 43 行有一个 vModelText,从名字上也可以看出来这是专门针对 <input> 的,因为只有这个元素是可以输入 text 的,其它以 vModel 开头的还有:

  • vModelCheckbox
  • vModelRadio
  • vModelSelect
  • vModelDynamic

但咱们想搞清楚的是中文输入法 bug,所以只看 vModelText 就行,其它的不用管。简单的扫了一眼,直觉告诉我问题出在了第 51 行:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

因为从命名上来看,.composing 是正在组合中的意思,我们用中文输入法打字的时候不就是正在组合中么:

正在组合中就 return,后面的代码也就不执行了,这也非常符合我们目前所遇到的状况。不过 e.target 上有 .composing 这个属性么?我们用原生来试一下:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

可以看到根本就没这个属性,我就说嘛!我怎么不记得还有这个属性,那这个属性肯定是 Vue 自己添加上去的。我们继续来看源码,在第 67、68 行我发现了这个:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

然后找到 onCompositionStart 和 onCompositionEnd 这两个函数:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

原来还真是 Vue 自己加上去的属性,不过在这之前我从来没听说过 compositionstart 和 compositionend 这两个事件,盲猜肯定是在中文输入法(其实这么说不太准确,准确来说应该是所有需要把英文字母的组合转换成另外一种文字的输入法)输入的时候会触发的事件,我们来试一下:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

可以看到我们用英文打字时并没有打印出任何东西来,这代表了没有触发事件,当换成中文输入法时就能触发事件并打印出 CompositionEvent 了。原本我以为这是个 bug,但看完源码后我意识到这是有意为之,但我觉得这种有意为之并不好,因为官网上明明说了 v-model === :value + @input,不过在中文输入法下表现却并不一致。当然我知道这也是出于好意,尤雨溪可能觉得中文输入法打字时产生的字母并没有什么有效信息,比方说我们在搜索框里搜一个鼠头:

我们获取到的值是 shu tou,但这个 shu tou 并不是个没用的信息,用它照样可以显示出当前的热点搜索:

然后随便一点击,就能看到一些:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

而且还有一个可能,就是本来就是想用英文搜,只不过是忘记了切换输入法:

我们的产品就属于这种,我们做的是海外业务,用的是英文,但产品忘记了切换输入法,结果就出现了这个 bug。

改进

他加上 .composing 的判断自然有他的道理,但大家仔细想想,如果有人遇到了和我相同的 bug,去看官网:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

那他会不会想到把 v-model 换成 :value + @input 就能够解决掉这个 bug?那不就是个简写么?意思不都是一样的么?谁能想得到啊家人们:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

但也不代表 .composing 没有意义,不过我觉得 com 不 composing 的控制权应该交给开发者,v-model 不是有各种修饰符么:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

可以搞个内置修饰符 .composing:

<input v-model.composing="value">           

不过我觉得尤雨溪可能觉得这样写比较麻烦所以才做了 v-model 默认就有 .composing 的判断,那这样也可以搞个 .nocomposing 修饰符嘛:

<input v-model.nocomposing="value">           

然后再在官网上标明 v-model 其实在中文输入法正在输入的情况下与 :value + @input 的表现并不一致,如果想要一致的话就加上 .nocomposing 修饰符:

<input v-model.nocomposing="value">           

后续

由于很多人对我产生了质疑,认为我不看文档,评论区也有好心人指出其实官网里有写,只是我没注意罢了:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

其实我很感激这位@用户28003832908...,因为如果不是他的话我还真不知道 Vue 官网里有这么一段话。当然我也因此遭受了许多质疑:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?
产品经理:能不能把 Vue 的中文输入法 bug 解决了?
产品经理:能不能把 Vue 的中文输入法 bug 解决了?
产品经理:能不能把 Vue 的中文输入法 bug 解决了?

反正就是觉得我不仔细看文档,非要自己瞎折腾,还有人把自己比作写说明书的人来苦笑啥用户都有,顺便阴阳怪气的说不能排除我看的那个瞬间官网确实刚好没显示相关内容的可能性。

当时是用手机看的评论,人家截了图,我明明记得没有看到过任何提示,但证据摆在那让我也开始怀疑自己了,难道真是自己真的看的不仔细?后来又去官网看了一遍,发现确实没有提示,于是我点开评论区的链接,这才明白过来是怎么一回事。

首先我要强调的是,自己一开始并不知道到底是哪里出了问题,用原生写了一遍发现没问题,再把原生的写法放到 Vue 里也没问题,最终才确认的是 v-model 的问题。

然后才去官网搜 v-model:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

搜到的 v-model 那章压根就没有任何的提示,我把 v-model 整章都截了图,不相信的可以仔细找下有没有提示:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

假如是你经过排查的话发现了是某个属性导致的(如v-xxx)那你是选择去 Vue 官网从头到尾花一两个小时仔细阅读一遍呢?还是直接在搜索框里搜这个 v-xxx 呢?

我觉得大多数人都会选择直接搜吧?关键是这章他就没写任何提示,如果不是评论区那位好心网友贴上链接我根本就不知道其实写了提示。

但问题在于这个提示没有写在 v-model 那章,直到我点开网友链接的时候才发现这章叫《表单输入绑定》

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

我知道肯定有人会说那你就不会搜索表单么:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

确实 v-model 是用在表单上的,当然也不只是能用在表单上,还可以用作组件的自定义 v-model 上。不过请原谅我是个直肠子,v-model 有让我感到疑惑的点我就只会在搜索框里搜 v-model,而不会先想一遍 v-model 是用在什么场景的,然后再去搜索那个场景。

就拿表单输入绑定的前面几项来举例子:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

假如你发现了 v-if 有问题,你是会在搜索框里搜 v-if 呢还是条件渲染呢?v-for 有问题是搜v-for 呢还是搜列表渲染呢?v-on 有问题不去搜 v-on 而是去搜索事件处理呗?

所以我觉得这是文档里很大的一个误导,我就是搜 v-model 后看到他说的那句:

产品经理:能不能把 Vue 的中文输入法 bug 解决了?

然后更加疑惑才去分析的源码,而不是我傻了吧唧的不看“说明书”就知道自己瞎鼓捣。当然也不是我修 bug 的时候为了研究为啥有问题就直接去看源码了,那时候正处于产品走查阶段着急上线呢!发现把 v-model 换成非简写形式就没问题了之后,放假了没事了才去看源码解答一下心中的疑惑。

原文链接:https://juejin.cn/post/7267728538567114789

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

继续阅读