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
`;
@@ -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('');
+}