diff --git a/packages/input/__tests__/input.spec.ts b/packages/input/__tests__/input.spec.ts
index cdb639f1d3..a62b97a263 100644
--- a/packages/input/__tests__/input.spec.ts
+++ b/packages/input/__tests__/input.spec.ts
@@ -45,7 +45,7 @@ describe('Input.vue', () => {
expect(nativeInput.placeholder).toBe('请输入内容')
expect(nativeInput.value).toBe('input')
expect(nativeInput.minLength).toBe(3)
- expect(nativeInput.maxLength).toBe(5)
+ // expect(nativeInput.maxLength).toBe(5) // The maxlength attribute is no longer a native attribute
vm.input = 'text'
await sleep()
@@ -68,6 +68,61 @@ describe('Input.vue', () => {
expect(inputElm.element.disabled).not.toBeNull()
})
+ describe('test emoji',()=>{
+ test('el-input should minimize value between emoji length and maxLength', async () => {
+ const wrapper = _mount({
+ template: ``,
+ setup() {
+ const inputVal = ref('12🌚')
+ return { inputVal }
+ },
+ })
+ const vm = wrapper.vm
+ const inputElm = wrapper.find('input')
+ const nativeInput = inputElm.element
+ expect(nativeInput.value).toBe('12🌚')
+
+ const elCount = wrapper.find('.el-input__count-inner')
+ expect(elCount.exists()).toBe(true)
+ expect(elCount.text()).toBe('3/4')
+
+ vm.inputVal = '1👌3😄'
+ await sleep()
+ expect(nativeInput.value).toBe('1👌3😄')
+ expect(elCount.text()).toBe('4/4')
+
+ vm.inputVal = '哈哈1👌3😄'
+ await sleep()
+ expect(nativeInput.value).toBe('哈哈1👌3😄')
+ expect(elCount.text()).toBe('6/4')
+ expect(vm.$el.classList.contains('is-exceed')).toBe(true)
+ })
+
+ test('textarea should minimize value between emoji length and maxLength', async () => {
+ const wrapper = _mount({
+ template: ``,
+ setup() {
+ const inputVal = ref('啊好😄')
+ return { inputVal }
+ },
+ })
+ const vm = wrapper.vm
+ const inputElm = wrapper.find('textarea')
+ const nativeInput = inputElm.element
+ expect(nativeInput.value).toBe('啊好😄')
+
+ const elCount = wrapper.find('.el-input__count')
+ expect(elCount.exists()).toBe(true)
+ expect(elCount.text()).toBe('3/4')
+
+ vm.inputVal = '哈哈1👌3😄'
+ await sleep()
+ expect(nativeInput.value).toBe('哈哈1👌3😄')
+ expect(elCount.text()).toBe('6/4')
+ expect(vm.$el.classList.contains('is-exceed')).toBe(true)
+ })
+ })
+
test('suffixIcon', () => {
const wrapper = _mount({
template: ``,
diff --git a/packages/input/src/index.vue b/packages/input/src/index.vue
index 35d6bb6ebe..22263c909f 100644
--- a/packages/input/src/index.vue
+++ b/packages/input/src/index.vue
@@ -70,7 +70,7 @@
- {{ textLength }}/{{ upperLimit }}
+ {{ textLength }}/{{ maxlength }}
@@ -103,7 +103,7 @@
@keydown="handleKeydown"
>
- {{ textLength }}/{{ upperLimit }}
+ {{ textLength }}/{{ maxlength }}
@@ -222,6 +222,9 @@ export default defineComponent({
type: Object,
default: () => ({}),
},
+ maxlength: {
+ type: [Number, String],
+ },
},
emits: [UPDATE_MODEL_EVENT, 'input', 'change', 'focus', 'blur', 'clear',
@@ -254,7 +257,6 @@ export default defineComponent({
}))
const inputDisabled = computed(() => props.disabled || elForm.disabled)
const nativeInputValue = computed(() => (props.modelValue === null || props.modelValue === undefined) ? '' : String(props.modelValue))
- const upperLimit = computed(() => ctx.attrs.maxlength)
const showClear = computed(() => {
return props.clearable &&
!inputDisabled.value &&
@@ -270,18 +272,18 @@ export default defineComponent({
})
const isWordLimitVisible = computed(() => {
return props.showWordLimit &&
- ctx.attrs.maxlength &&
+ props.maxlength &&
(props.type === 'text' || props.type === 'textarea') &&
!inputDisabled.value &&
!props.readonly &&
!props.showPassword
})
const textLength = computed(() => {
- return typeof props.modelValue === 'number' ? String(props.modelValue).length : (props.modelValue || '').length
+ return Array.from(nativeInputValue.value).length
})
const inputExceed = computed(() => {
// show exceed style if length of initial value greater then maxlength
- return isWordLimitVisible.value && (textLength.value > upperLimit.value)
+ return isWordLimitVisible.value && (textLength.value > Number(props.maxlength))
})
const resizeTextarea = () => {
@@ -332,7 +334,7 @@ export default defineComponent({
}
const handleInput = event => {
- const { value } = event.target
+ let { value } = event.target
// should not emit input during composition
// see: https://github.com/ElemeFE/element/issues/10516
@@ -340,7 +342,14 @@ export default defineComponent({
// hack for https://github.com/ElemeFE/element/issues/8548
// should remove the following line when we don't support IE
- if (value === nativeInputValue.value) return
+ if (value === nativeInputValue.value ) return
+
+ // if set maxlength
+ if (props.maxlength) {
+ const sliceIndex = inputExceed.value ? textLength.value : props.maxlength
+ // Convert value to an array for get a right lenght
+ value = Array.from(value).slice(0, Number(sliceIndex)).join('')
+ }
ctx.emit(UPDATE_MODEL_EVENT, value)
ctx.emit('input', value)
@@ -481,7 +490,6 @@ export default defineComponent({
showClear,
showPwdVisible,
isWordLimitVisible,
- upperLimit,
textLength,
hovering,
inputExceed,
diff --git a/website/docs/en-US/input.md b/website/docs/en-US/input.md
index 0f35c55882..b9cb1af250 100644
--- a/website/docs/en-US/input.md
+++ b/website/docs/en-US/input.md
@@ -568,7 +568,7 @@ export default defineComponent({
### Limit length
-:::demo `maxlength` and `minlength` are attributes of native input, they declare a limit on the number of characters a user can input. The "number of characters" is measured using JavaScript string length.Setting the `maxlength` prop for a text or textarea type of Input can limit the length of input value, allows you to show word count by setting `show-word-limit` to `true` at the same time.
+:::demo `maxlength` and `minlength` attributes of input, they declare a limit on the number of characters a user can input. The "number of characters" is measured using JavaScript string length.Setting the `maxlength` prop for a text or textarea type of Input can limit the length of input value, allows you to show word count by setting `show-word-limit` to `true` at the same time.
```html