问题描述
今天旧项目发现个问题,使用手写输入法时,输入第一个字后接着输入第二个字,第二个字会被删掉,导致无法正常输入。
问题复现
最小复现组件代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <template> <view class="base-search-input-container"> <view class="input-area"> <view class="input-box"> <input v-model="inputVal" type="text" confirm-type="search" :placeholder="placeholder" /> </view> </view> </view> </template>
<script setup> import { computed, defineEmits, defineProps } from 'vue'
const emits = defineEmits(['update:value', 'search', 'input']) const props = defineProps({ value: { type: String, required: true }, placeholder: { type: String, default: '请输入' } })
const inputVal = computed({ get: () => props.value, set: (val) => emits('update:value', val) })
</script>
<style scoped> .base-search-input-container { display: flex; border: 1px solid #ccc; padding: 10px; } .input-area { flex: 1; } </style>
|
非常普通的一个input的组件啊
问题原因分析
手写输入流程
- 用户手写第一个字时,该字处于候选状态,此时不会触发
@input事件 - 当用户开始手写第二个字时,第一个字被确认,此时触发
@input事件 - 问题在于:此时
@input事件返回的参数val可能只包含第一个字的信息,而不是完整的输入内容
这种方式在手写输入场景下,会导致获取到的输入值不完整,从而丢失第二个字。
解决方案
监听 compositionend 事件,在 IME 组合输入完全结束后再同步数据,避免在组合过程中干扰输入框。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const inputValue = ref(props.value) const isComposing = ref(false)
watch(() => props.value, (newVal) => { if (!isComposing.value) { inputValue.value = newVal } })
function handleInput(e) { inputValue.value = e.target.value if (!isComposing.value) { emit('update:value', inputValue.value) } }
function handleCompositionEnd(e) { isComposing.value = false const finalValue = e.target.value inputValue.value = finalValue emit('update:value', finalValue) }
|
结语
这个项目是22年用hbuild x创建的uni-app项目,我用后续cli创建的项目没有这个问题,也就是说这问题已经被修复了。
再就是uni-app x 已经支持 Android/IOS/鸿蒙net/Web/微信小程序,不再是当年只支持Android的模样, 后续要用是否该使用uni-app x了?