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

news2025/1/11 16:42:04

前言

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

这玩意在前端也挺好实现的,就 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>

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

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

中文输入法

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

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

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

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

<input>

document.querySelector('input').oninput = ({
  target: { value }
}) => console.log(value)

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

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

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

<template>
  <input ref="input">
</template>

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

const input = ref('');
onMounted(() => input.value.oninput = ({ target: { value } }) => console.log(value))
</script>

<style>
html, body {
  background: #222;
}

input {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  width: 300px;
  height: 30px;
  padding: 0 10px;
  border: 1px solid #395e71;
  border-radius: 16px;
  color: antiquewhite;
  background: none;
  outline: none;
}
</style>

结果居然是好的:

接下来我陷入了短暂的沉思:原来的代码在刨除掉业务部分后在 <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 官网里就是这么写的:

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

源码

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

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

  • vModelCheckbox
  • vModelRadio
  • vModelSelect
  • vModelDynamic

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

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

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

document.querySelector('input').oninput = ({
  target: { composing }
}) => console.log('composing: ', composing)

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

然后找到 onCompositionStartonCompositionEnd 这两个函数:

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

document.querySelector('input').addEventListener('compositionstart', e => console.log(e))

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

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

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

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

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

改进

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

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

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

可以搞个内置修饰符 .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">

结语

大家可以去提个 PR,这可是一个成为 Vue Contributor 的好机会。如果尤雨溪不明白为什么要这么改时,你可以把我这篇文章的链接发给他看,相信他就明白了 v-model 有可能会给大家带来的困境了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/886283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAP MM学习笔记25- SAP中 基本数量单位,发注单位,发注价格单位

SAP 的 MM Master 中有 3种单位。 1&#xff0c;基本数量单位&#xff08; 基本订单单位&#xff0c; 库存管理的最小单位&#xff09; 2&#xff0c;发注单位&#xff08;订单单位&#xff09; 3&#xff0c;发注价格单位&#xff08;订单价格单位&#xff09; 管理 SAP 库…

【jenkins】jenkins流水线构建打包jar,生成docker镜像,重启docker服务的过程,在jenkins上一键完成,实现提交代码自动构建的功能

【jenkins】jenkins流水线构建打包jar&#xff0c;生成docker镜像&#xff0c;重启docker服务的过程&#xff0c;在jenkins上一键完成&#xff0c;实现提交代码自动构建&#xff0c;服务重启&#xff0c;服务发布的功能。一键实现。非常的舒服。 1. 启动脚本 shell脚本 这是 s…

测试部门来了个00后卷王之王,老油条感叹真干不过,但是...

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&…

SystemVerilog之接口详解

1.入门实例 测试平台连接到 arbiter的例子&#xff1a;包括测试平台, arbiter仲裁器, 时钟发生器 和连接的信号。 ㅤㅤㅤ ㅤ ㅤㅤㅤㅤㅤ Arbiter里面可以自定义发送的权重&#xff0c; 是轮询还是自定义 grant表示仲裁出来的是哪一个&#xff0c;也即只有0&#xff0c;1&am…

基于springboot校园缴费管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

MySQL 索引为什么使用 B+ 树,而不使用红黑树 / B 树 ?

面试官问 &#xff1a;索引为什么使用 B 树&#xff0c;而不使用 B 树&#xff0c;不使用红黑树呢 首先 B 树和 B 树 都是多叉搜索树&#xff0c;然后我们先来观察一下 B 树和 B 树的数据结构&#xff1a; B 树的数据结构实现 >> B 树的数据结构实现 >> 【B 树相…

JAVASE---数组的定义与使用

数组的基本概念 什么是数组 数组是具有相同类型元素的集合&#xff0c;在内存中连续存储。 1. 数组中存放的元素其类型相同 2. 数组的空间是连在一起的 3. 每个空间有自己的编号&#xff0c;起始位置的编号为0&#xff0c;即数组的下标 数组的创建及初始化 数组的创建 T[…

【Unity】UI的一些简单知识

Canvas 新建一个Canvas Render Mode Canvas 中有一个Render Mode&#xff08;渲染模式&#xff09;&#xff0c;有三种渲染模式: Screen Space-Overlay &#xff08;屏幕空间&#xff09;Screen Space-Camara 、 World Space 其中&#xff0c;Space- Overlay是默认显示在…

Docker容器基础

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、Docker概述1、docker是什么2、Docker的设计宗旨3、容器在内核中支持2种重要技术&#xff1a; 三、Docker的核心概念四、Docker相关命令1.安装依赖包2.设置阿里云…

《qt quick核心编程》笔记四

11 Model/View Delegate实际上可以看成是Item的一个模板 11.1 ListView ListView用于显示一个条目列表&#xff0c;数据来自于Model&#xff0c;每个条目的外观来自于Delegate 要使用ListView必须指定一个Model、一个Delegate Model可以是QML内建类型&#xff0c;如ListModel…

2023年武汉市中等职业教育网络安全赛项竞赛试题——综合靶机渗透测试解析教程

任务一&#xff1a;综合靶机渗透测试 任务环境说明&#xff1a; 服务器场景&#xff1a;ZHCS-2&#xff08;关闭连接&#xff09; 服务器场景操作系统&#xff1a;版本不详 大家需要靶机环境可以私信我获取 1.扫描目标靶机将靶机开放的所有端口&#xff0c;当作flag提交&am…

【学会动态规划】乘积为正数的最长子数组长度(21)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…

ESP32 历程解析

最近在用esp32做项目&#xff0c;记录一下 使用的esp32 的官方历程的作用 一、USB历程 1.host 1) cdc_acm_host 这个历程可以用来驱动 usb的虚拟串口从机 cdc__vcp 和 cdc_acm 方式虚拟的串口需要根据自己的设备 修改 VID 和 PID /*cdc-acm*/ #define EXAMPLE_US…

非计算机科班如何顺利转码进入计算机领域?

文章目录 如何规划才能实现转码&#xff1f;计算机岗位发展前景&#xff1f;现阶段转码 总结 &#x1f389;欢迎来到Java学习路线专栏~探索非计算机科班如何顺利转码进入计算机领域 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f3…

8.16日 算法做题【4道题】

8. 分行从上往下打印二叉树 &#xff08; 利用两个队列遍历 &#xff09; 利用数组个数 进行遍历 原题链接 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(N…

工业设备状态监测如何实现从技术试点到规模实施?

工业企业正逐步引入基于人工智能的持续监控设备健康状况系统&#xff0c;这对工业维护领域带来了颠覆性的影响。然而&#xff0c;与任何新技术一样&#xff0c;要实现其最大价值&#xff0c;需要克服一些挑战。在数字化转型中&#xff0c;成功实现工业设备状态监测的从技术试点…

企业什么时候需要PMO?PMO的作用和职责是什么?

在当今复杂的商业环境中&#xff0c;企业依靠高效的项目管理来推动成功和实现战略目标。这就是**项目管理办公室**&#xff08;PMO&#xff09;发挥作用的地方。那么&#xff0c;PMO在企业中的作用和职责究竟是什么&#xff1f;本文就这个问题来做个探讨。 PMO &#xff08;项…

第 3 章 稀疏数组和队列(1)

3.1 稀疏 sparsearray 数组 3.1.1先看一个实际的需求 编写的五子棋程序中&#xff0c;有存盘退出和续上盘的功能。 分析问题: 因为该二维数组的很多值是默认值 0.因此记录了很多没有意义的数据.->稀疏数组 3.1.2基本介绍 当一个数组中大部分元素为 0&#xff0c;或者为同…

python进阶之符号计算概述SymPy

一、概述 1.1SymPy简介 SymPy 是一个由 Python 编写的符号计算库&#xff0c;它的目标是成为一个全功能的计算机代数系统&#xff0c;同时保持代码简洁、易于理解和扩展。它完全由 Python 写成&#xff0c;不依赖于外部库。SymPy 支持符号计算、高精度计算、模式匹配、绘图、解…

搭建Excel服务器

1、下载Excel服务器 下载地址 2、解压文件 3、打开服务器 4、服务器运行信息 5、连接测试 打开客户端 6、登录到服务器 默认账号 密码 admin 3 修改文件保存路径(服务器端点击配置) 7、客户端整体界面 8、配置权限 9、设计模板 10、其他用户登录就可以填写信息 11、用户&#…