fix(Field): improve cursor position handling for emoji input and formatting (#13711)

This commit is contained in:
inottn
2025-12-13 21:39:39 +08:00
committed by GitHub
parent 68325f98db
commit 497e3d58ec
2 changed files with 39 additions and 5 deletions

View File

@@ -329,8 +329,7 @@ export default defineComponent({
// When the value length exceeds maxlength,
// record the excess length for correcting the cursor position.
// https://github.com/youzan/vant/issues/11289
const limitDiffLen =
getStringLength(originalValue) - getStringLength(value);
const limitDiffLen = originalValue.length - value.length;
// https://github.com/youzan/vant/issues/13058
if (props.type === 'number' || props.type === 'digit') {
@@ -368,8 +367,7 @@ export default defineComponent({
const bcoVal = cutString(originalValue, selectionEnd!);
// Record the length change of `bcoVal` after formatting,
// which is used to correct the cursor position.
formatterDiffLen =
getStringLength(formatter(bcoVal)) - getStringLength(bcoVal);
formatterDiffLen = formatter(bcoVal).length - bcoVal.length;
}
}
@@ -380,7 +378,7 @@ export default defineComponent({
inputRef.value.value = value;
if (isDef(selectionStart) && isDef(selectionEnd)) {
const valueLen = getStringLength(value);
const valueLen = value.length;
if (limitDiffLen) {
selectionStart -= limitDiffLen;

View File

@@ -608,3 +608,39 @@ test("should not be set label's for attribute when using input slot", async () =
wrapper.find('.van-field__label label').attributes('for'),
).toBeUndefined();
});
test('should update selection range correctly when inputting text into string with emoji', async () => {
const wrapper = mount(Field, {
props: {
maxlength: 2,
modelValue: '😀😀',
},
});
const input = wrapper.find('input');
await input.trigger('focus');
input.element.value = '😀😀😀';
input.element.selectionEnd = 6;
input.trigger('input');
expect(input.element.selectionEnd).toEqual(4);
});
test('should update selection range correctly when using formatter with emoji', async () => {
const wrapper = mount(Field, {
props: {
modelValue: '',
formatter: (val) => val.replace('1', '😀😀'),
},
});
const input = wrapper.find('input');
await input.trigger('focus');
input.element.value = '1';
input.element.selectionEnd = 1;
input.trigger('input');
expect(input.element.selectionEnd).toEqual(4);
});