diff --git a/packages/vant/src/field/Field.tsx b/packages/vant/src/field/Field.tsx index 41aa3166a..03957c292 100644 --- a/packages/vant/src/field/Field.tsx +++ b/packages/vant/src/field/Field.tsx @@ -27,12 +27,14 @@ import { createNamespace, } from '../utils'; import { + cutString, runSyncRule, endComposing, mapInputType, startComposing, getRuleMessage, resizeTextarea, + getStringLength, runRuleValidator, } from './utils'; import { cellSharedProps } from '../cell/Cell'; @@ -255,12 +257,12 @@ export default defineComponent({ // see: https://github.com/youzan/vant/issues/5033 const limitValueLength = (value: string) => { const { maxlength } = props; - if (isDef(maxlength) && value.length > maxlength) { + if (isDef(maxlength) && getStringLength(value) > maxlength) { const modelValue = getModelValue(); - if (modelValue && modelValue.length === +maxlength) { + if (modelValue && getStringLength(modelValue) === +maxlength) { return modelValue; } - return value.slice(0, +maxlength); + return cutString(value, +maxlength); } return value; }; @@ -462,7 +464,7 @@ export default defineComponent({ const renderWordLimit = () => { if (props.showWordLimit && props.maxlength) { - const count = getModelValue().length; + const count = getStringLength(getModelValue()); return (
{count}/{props.maxlength} diff --git a/packages/vant/src/field/test/__snapshots__/index.spec.js.snap b/packages/vant/src/field/test/__snapshots__/index.spec.js.snap index 700d799ac..3d851b865 100644 --- a/packages/vant/src/field/test/__snapshots__/index.spec.js.snap +++ b/packages/vant/src/field/test/__snapshots__/index.spec.js.snap @@ -62,21 +62,11 @@ exports[`should render textarea when type is textarea 1`] = ` `; exports[`should render word limit correctly 1`] = ` -
-
-
- -
-
- - 3 - - /3 -
-
+
+ + 3 + + /3
`; @@ -117,3 +107,12 @@ exports[`should render word limit correctly when modelValue is undefined 1`] = `
`; + +exports[`should render word limit with emoji correctly 1`] = ` +
+ + 2 + + /3 +
+`; diff --git a/packages/vant/src/field/test/index.spec.js b/packages/vant/src/field/test/index.spec.js index 676f8c3ae..8a9258124 100644 --- a/packages/vant/src/field/test/index.spec.js +++ b/packages/vant/src/field/test/index.spec.js @@ -343,7 +343,7 @@ test('should render word limit correctly', () => { showWordLimit: true, }, }); - expect(wrapper.html()).toMatchSnapshot(); + expect(wrapper.find('.van-field__word-limit').html()).toMatchSnapshot(); }); test('should render word limit correctly when modelValue is undefined', () => { @@ -475,3 +475,26 @@ test('should render error-message slot correctly', async () => { expect(wrapper.find('.van-field__error-message').html()).toMatchSnapshot(); }); + +test('should limit maxlength with emoji correctly', async () => { + const wrapper = mount(Field, { + props: { + maxlength: 3, + modelValue: '😀😀😀😀', + }, + }); + + const input = wrapper.find('input'); + expect(input.element.value).toEqual('😀😀😀'); +}); + +test('should render word limit with emoji correctly', () => { + const wrapper = mount(Field, { + props: { + modelValue: '😀😀', + maxlength: 3, + showWordLimit: true, + }, + }); + expect(wrapper.find('.van-field__word-limit').html()).toMatchSnapshot(); +}); diff --git a/packages/vant/src/field/utils.ts b/packages/vant/src/field/utils.ts index d55f97f81..9c9c3c6a0 100644 --- a/packages/vant/src/field/utils.ts +++ b/packages/vant/src/field/utils.ts @@ -107,3 +107,14 @@ export function mapInputType(type: FieldType): { return { type }; } + +// get correct length of emoji +// https://github.com/youzan/vant/issues/10032 +export function getStringLength(str: string) { + return [...str].length; +} + +// cut string with emoji +export function cutString(str: string, maxlength: number) { + return [...str].slice(0, maxlength).join(''); +}