From e92882ebf3a9dca444a6efae2d61f24a5065606a Mon Sep 17 00:00:00 2001 From: devin Date: Wed, 12 Nov 2025 15:27:18 +0800 Subject: [PATCH 1/3] =?UTF-8?q?style:=20=E5=A2=9E=E5=8A=A0=E9=83=A8?= =?UTF-8?q?=E5=88=86eslint=20=E7=A9=BA=E6=A0=BC=E7=9B=B8=E5=85=B3=E8=A7=84?= =?UTF-8?q?=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 8 +++++++- .vscode/settings.json | 7 +++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index ae1ee6751..1e1c75494 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -19,6 +19,7 @@ module.exports = { 'quote-props': ['warn', 'as-needed'], 'comma-dangle': ['error', 'only-multiline'], camelcase: ['error', { properties: 'never' }], + 'array-bracket-spacing': 'warn', 'arrow-spacing': 'warn', 'block-spacing': 'warn', @@ -30,12 +31,17 @@ module.exports = { 'object-curly-spacing': ['warn', 'always'], 'rest-spread-spacing': 'warn', 'switch-colon-spacing': 'error', + 'func-call-spacing': 'warn', 'semi-spacing': 'warn', 'template-curly-spacing': 'warn', 'template-tag-spacing': 'warn', 'yield-star-spacing': 'warn', - semi: ['warn', 'always'], + 'space-unary-ops': 'warn', + 'no-multi-spaces': 'warn', + 'no-mixed-spaces-and-tabs': 'warn', 'no-trailing-spaces': 'warn', + + semi: ['warn', 'always'], 'prefer-template': 'error', 'prefer-spread': 'error', 'no-var': 'error', diff --git a/.vscode/settings.json b/.vscode/settings.json index b8b8dd50c..89532e024 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,12 +3,15 @@ "explorer.fileNesting.patterns": { "package.json": "package-lock.json, yarn.lock, pnpm-lock.yaml,pnpm-workspace.yaml,.npmrc,.gitignore,LICENSE.md", ".eslintrc.js": ".prettierrc.js", - "README.md": "README.en.md", + "README.md": "README.en.md" }, "outline.showFiles": true, "files.exclude": { "packages/opendesign/dist": true, "packages/opendesign/es": true, "packages/opendesign/lib": true + }, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit" } -} \ No newline at end of file +} -- Gitee From aa0e682827ba7ed64a63a5f58a8b3f6f3cdb7619 Mon Sep 17 00:00:00 2001 From: devin Date: Mon, 17 Nov 2025 16:48:52 +0800 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=E5=8F=98=E9=87=8F=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/opendesign/src/_headless/use-input.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/opendesign/src/_headless/use-input.ts b/packages/opendesign/src/_headless/use-input.ts index 5c6255987..d6501fe61 100644 --- a/packages/opendesign/src/_headless/use-input.ts +++ b/packages/opendesign/src/_headless/use-input.ts @@ -46,13 +46,13 @@ export function useInput(options: InputOptionT) { return isFunction(calculateLength) ? calculateLength(v) : v?.length; }; - const uncontroledValue = ref(defaultValue); - const controledValue = modelValue; + const uncontrolledValue = ref(defaultValue); + const controlledValue = modelValue; // 当前值 const computedValue = computed(() => { - const cv = controledValue?.value; - const ucv = uncontroledValue.value ?? ''; + const cv = controlledValue?.value; + const ucv = uncontrolledValue.value ?? ''; return cv ?? ucv; }); @@ -144,7 +144,7 @@ export function useInput(options: InputOptionT) { ); const updateValue = (value: string) => { - uncontroledValue.value = value; + uncontrolledValue.value = value; emitUpdate(value); }; -- Gitee From e8a01e365aff64a9549ae93d61c39490d2a5a7e6 Mon Sep 17 00:00:00 2001 From: devin Date: Tue, 18 Nov 2025 10:22:26 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=20feat(in-input):=20=E5=BD=93inputOnOutlim?= =?UTF-8?q?it=E4=B8=BAfalse=E6=97=B6=EF=BC=8C=E8=BE=93=E5=85=A5=EF=BC=88?= =?UTF-8?q?=E5=A6=82=E7=B2=98=E8=B4=B4=EF=BC=89=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E9=95=BF=E5=BA=A6=E8=B6=85=E5=87=BAmaxLength=EF=BC=8C=E8=BF=99?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E6=88=AA=E6=96=AD=EF=BC=9BvalueOnInvalidChan?= =?UTF-8?q?ge=E6=94=AF=E6=8C=81boolean=E5=80=BC=EF=BC=8C[true]=EF=BC=9A?= =?UTF-8?q?=E7=BA=A0=E6=AD=A3=E4=B8=BA=E4=B8=8A=E4=B8=80=E6=AC=A1=E5=90=88?= =?UTF-8?q?=E6=B3=95=E7=9A=84=E5=80=BC(=E5=A6=82=E6=9E=9C=E4=B8=8A?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=E5=90=88=E6=B3=95=E5=80=BC=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=EF=BC=8C=E5=88=99=E4=B8=8D=E5=A4=84?= =?UTF-8?q?=E7=90=86);=20[false|undefined]:=20=E4=B8=8D=E5=A4=84=E7=90=86?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 7 +++- .../in-input/__demo__/TheIndex.vue | 13 +++--- .../src/_components/in-input/types.ts | 6 +-- .../src/_components/in-textarea/types.ts | 6 +-- .../opendesign/src/_headless/use-input.ts | 42 +++++++++++++------ 5 files changed, 48 insertions(+), 26 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1e1c75494..8d07e9839 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -40,6 +40,11 @@ module.exports = { 'no-multi-spaces': 'warn', 'no-mixed-spaces-and-tabs': 'warn', 'no-trailing-spaces': 'warn', + 'spaced-comment': 'warn', + 'space-infix-ops': 'warn', + + 'eol-last': 'warn', + indent: ['warn', 2], semi: ['warn', 'always'], 'prefer-template': 'error', @@ -87,4 +92,4 @@ module.exports = { } ], }, -}; \ No newline at end of file +}; diff --git a/packages/opendesign/src/_components/in-input/__demo__/TheIndex.vue b/packages/opendesign/src/_components/in-input/__demo__/TheIndex.vue index c406ad8b9..9e058221a 100644 --- a/packages/opendesign/src/_components/in-input/__demo__/TheIndex.vue +++ b/packages/opendesign/src/_components/in-input/__demo__/TheIndex.vue @@ -3,7 +3,7 @@ import '../style'; import InInput from '../InInput.vue'; import { ref } from 'vue'; -const inputVal = ref('124567890'); +const inputVal = ref('124567123'); const printEvent = (evt: string, v?: string) => { console.log(`[${evt}]`, v ?? '', 'inputVal:', inputVal.value); @@ -11,7 +11,7 @@ const printEvent = (evt: string, v?: string) => { const disabled = ref(false); const maxLength = ref(6); -const minLength = ref(4); +const minLength = ref(2); const toggle = () => { disabled.value = !disabled.value; maxLength.value = 5; @@ -29,6 +29,7 @@ const validate = (value: string): boolean => { const onUpdate = (val: string) => { inputVal.value = val; + console.log('onUpdate', val); }; const format = (val: string) => { @@ -37,7 +38,7 @@ const format = (val: string) => { const valueOnInvalidChange = (currentValue: string, lastValid: string) => { console.log('valueOnInvalidChange:', currentValue, lastValid); - return lastValid; + return lastValid || currentValue; }; const onChange = (currentValue: string, lastValue: string) => { @@ -67,7 +68,7 @@ window.setInterval(() => { @clear="() => printEvent('clear')" @blur="() => printEvent('blur')" @change="onChange" - @input="(e, value) => printEvent('input', value)" + @input="(e:Event, value:string) => printEvent('input', value)" @focus="() => printEvent('focus')" @press-enter="() => printEvent('press-enter')" clearable @@ -87,8 +88,8 @@ window.setInterval(() => { :validate="validate" @clear="() => printEvent('clear')" @blur="() => printEvent('blur')" - @change="(v) => printEvent('change', v)" - @input="() => printEvent('input')" + @change="(v:string) => printEvent('change', v)" + @input="(_e:Event, v:string) => printEvent('input', v)" @focus="() => printEvent('focus')" @press-enter="() => printEvent('press-enter')" clearable diff --git a/packages/opendesign/src/_components/in-input/types.ts b/packages/opendesign/src/_components/in-input/types.ts index 10df89892..110183304 100644 --- a/packages/opendesign/src/_components/in-input/types.ts +++ b/packages/opendesign/src/_components/in-input/types.ts @@ -81,7 +81,7 @@ export const inInputProps = { type: Function as PropType<(val: string) => number>, }, /** - * @zh-CN 超过最大字符长度时是否允许输入 + * @zh-CN 超过最大字符长度时是否允许输入,当为false时,输入长度超出maxLength会被截断 * @en-US Whether input is allowed when the maximum character length is exceeded. * @default true */ @@ -104,11 +104,11 @@ export const inInputProps = { type: Function as PropType<(value: string) => boolean>, }, /** - * @zh-CN 输入为无效值时,在blur/pressEnter时的回调,返回值为纠正后的值 + * @zh-CN 输入为无效值时,在blur/pressEnter时的回调,返回值为纠正后的值;当输入值不合法时的处理方式:[true]:纠正为上一次合法的值(如果上一次合法值为空字符串,则不处理); [false|undefined]: 不处理;[function]: 使用函数的返回值 * @en-US When the input value is an invalid value, the callback during blur/pressEnter returns the corrected value. */ valueOnInvalidChange: { - type: Function as PropType<(inputValue: string, lastValidInputValue: string) => string>, + type: [Boolean, Function as PropType<(inputValue: string, lastValidInputValue: string) => string>], }, /** * @zh-CN 显示密码的方式 diff --git a/packages/opendesign/src/_components/in-textarea/types.ts b/packages/opendesign/src/_components/in-textarea/types.ts index 69b5bd3e3..2df34eae8 100644 --- a/packages/opendesign/src/_components/in-textarea/types.ts +++ b/packages/opendesign/src/_components/in-textarea/types.ts @@ -62,11 +62,11 @@ export const inTextareaProps = { type: Function as PropType<(value: string) => boolean>, }, /** - * @zh-CN 输入非法值时的回调 - * @en-US Callback when input value is invalid + * @zh-CN 输入为无效值时,在blur/pressEnter时的回调,返回值为纠正后的值;当输入值不合法时的处理方式:[true]:纠正为上一次合法的值(如果上一次合法值为空字符串,则不处理); [false|undefined]: 不处理;[function]: 使用函数的返回值 + * @en-US When the input value is an invalid value, the callback during blur/pressEnter returns the corrected value. */ valueOnInvalidChange: { - type: Function as PropType<(inputValue: string, lastValidInputValue: string) => string>, + type: [Boolean, Function as PropType<(inputValue: string, lastValidInputValue: string) => string>], }, /** * @zh-CN 同 textarea 的 rows 属性 diff --git a/packages/opendesign/src/_headless/use-input.ts b/packages/opendesign/src/_headless/use-input.ts index d6501fe61..9a2d2b979 100644 --- a/packages/opendesign/src/_headless/use-input.ts +++ b/packages/opendesign/src/_headless/use-input.ts @@ -7,7 +7,7 @@ import { ref, computed, Ref, watch, nextTick } from 'vue'; export type UseInputEmitsT = { // 仅在输入框失焦或按下回车时触发 (e: 'change', value: string, lastValue: string): void; - // 用户输入时触发 + // 用户输入时(键盘输入、粘贴等)触发,value为当前输入的值 (e: 'input', evt: Event, value: string): void; // 输入框获取焦点时触发 (e: 'focus', evt: FocusEvent): void; @@ -24,7 +24,8 @@ export interface InputOptionT { emits: UseInputEmitsT; emitUpdate: (value: string) => void; validate?: (value: string) => boolean; - valueOnInvalidChange?: (inputValue: string, lastValidInputValue: string) => string; + // 当输入值不合法时的处理方式:[true]:纠正为上一次合法的值(如果上一次合法值为空字符串,则不处理); [false|undefined]: 不处理;[function]: 使用函数的返回值 + valueOnInvalidChange?: boolean | ((inputValue: string, lastValidInputValue: string) => string); format?: (value: string) => string; maxLength?: Ref; minLength?: Ref; @@ -109,7 +110,7 @@ export function useInput(options: InputOptionT) { // 值可用状态 const isValid = ref(true); - /**` + /** * 校验是否值有效,如果值为空,始终有效 */ const validateValue = (value: string) => { @@ -146,7 +147,10 @@ export function useInput(options: InputOptionT) { const updateValue = (value: string) => { uncontrolledValue.value = value; - emitUpdate(value); + // 判断值是否变化,有变化再触发事件 + if (value !== computedValue.value) { + emitUpdate(value); + } }; const getValidValue = () => { @@ -154,10 +158,10 @@ export function useInput(options: InputOptionT) { // 值有效性校验 if (!isValid.value) { if (isFunction(valueOnInvalidChange)) { - // 这调用valueOnInvalidChange回调获取对应回调值 + // 调用valueOnInvalidChange回调获取对应回调值 validVal = valueOnInvalidChange(computedValue.value, lastValidValue); validateValue(validVal); - } else { + } else if (valueOnInvalidChange === true && lastValidValue !== ''){ // 回退到上一次有效值 validVal = lastValidValue; isValid.value = true; @@ -169,8 +173,10 @@ export function useInput(options: InputOptionT) { const emitChange = (value: string) => { if (value !== lastValue) { - emits('change', computedValue.value, lastValue); - lastValue = computedValue.value; + nextTick(() => { + emits('change', computedValue.value, lastValue); + lastValue = computedValue.value; + }); } }; @@ -181,15 +187,18 @@ export function useInput(options: InputOptionT) { } }; - const isAllowedToInput = (value: string) => { - if (inputOnOutlimit?.value) { + const isAllowedToInputOnOutLimit = (value: string) => { + // 未设置最大长度或者允许查出最大长度后可继续输入 + if (!isUndefined(maxLength?.value) && inputOnOutlimit?.value === true) { return true; } + const len = calculateStringLength(value); const isLower = validateMaxLength(len); if (isLower) { return true; } + // 超出长度限制,且为字符长度减少,则支持操作 if (len < calculateStringLength(computedValue.value)) { return true; @@ -199,18 +208,25 @@ export function useInput(options: InputOptionT) { const handleInput = (e: Event) => { const value = (e.target as HTMLInputElement)?.value; + if (composition.isComposing.value) { // 解决在输入中文时,组件触发onUpdate时,显示值被刷新成输入前的值 displayValue.value = value; return; } - if (isAllowedToInput(value)) { - updateValue(value); + // 始终上报当前输入的值,可能经过校验、或截断后显示的值与输入的不一致 + emits('input', e, value); + + let newValue = value; - emits('input', e, value); + if (!isAllowedToInputOnOutLimit(value)) { + // 当超出长度限制不允许输入时,按照最大长度截断 + newValue = value.substring(0, maxLength?.value); } + updateValue(newValue); + nextTick(() => { keepNativeDisplayValue(); }); -- Gitee