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