diff --git a/docs/markdown/migrate-from-v2.zh-CN.md b/docs/markdown/migrate-from-v2.zh-CN.md
index ceabf40f5..5955f6ced 100644
--- a/docs/markdown/migrate-from-v2.zh-CN.md
+++ b/docs/markdown/migrate-from-v2.zh-CN.md
@@ -201,6 +201,10 @@ Vue 3.0 中增加了 `Teleport` 组件,提供将组件渲染到任意 DOM 位
- `trigger` 属性的默认值调整为 `click`
+#### Stepper
+
+- `async-change` 属性重命名为 `before-change`,并调整使用方法
+
#### SwipeCell
- `open` 事件的 `detail` 参数重命名为 `name`
diff --git a/src/stepper/README.md b/src/stepper/README.md
index 9358fe55a..cd3290802 100644
--- a/src/stepper/README.md
+++ b/src/stepper/README.md
@@ -71,10 +71,10 @@ export default {
```
-### Async Change
+### Before Change
```html
-
+
```
```js
@@ -85,22 +85,22 @@ export default {
setup() {
const value = ref(1);
- let timer;
- const onChange = (newValue) => {
- if (newValue === value.value) {
- return;
- }
-
+ const beforeChange = (value) => {
Toast.loading({ forbidClick: true });
- clearTimeout(this.timer);
- timer = setTimeout(() => {
- Toast.clear();
- value.value = newValue;
- }, 500);
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ Toast.clear();
+ // resolve 'true' or 'false'
+ resolve(true);
+ }, 500);
+ });
};
- return { value };
+ return {
+ value,
+ beforeChange,
+ };
},
};
```
@@ -116,7 +116,7 @@ export default {
### Props
| Attribute | Description | Type | Default |
-| --- | --- | --- | --- | --- |
+| --- | --- | --- | --- |
| v-model | Current value | _number \| string_ | - |
| min | Min value | _number \| string_ | `1` |
| max | Max value | _number \| string_ | - |
@@ -133,7 +133,7 @@ export default {
| disable-plus | Whether to disable plus button | _boolean_ | `false` |
| disable-minus | Whether to disable minus button | _boolean_ | `false` |
| disable-input | Whether to disable input | _boolean_ | `false` |
-| async-change | Whether to enable async change | _boolean_ | `false` | - |
+| before-change | Callback function before changing,return `false` to prevent change,support return Promise | _(value) => boolean \| Promise_ | `false` |
| show-plus | Whether to show plus button | _boolean_ | `true` |
| show-minus | Whether to show minus button | _boolean_ | `true` |
| long-press `v2.4.3` | Whether to allow long press | _boolean_ | `true` |
diff --git a/src/stepper/README.zh-CN.md b/src/stepper/README.zh-CN.md
index b57bcbf14..e324a14bc 100644
--- a/src/stepper/README.zh-CN.md
+++ b/src/stepper/README.zh-CN.md
@@ -93,10 +93,10 @@ export default {
### 异步变更
-如果需要异步地修改输入框的值,可以设置 `async-change` 属性,并在 `change` 事件中手动修改 `value`。
+通过 `before-change` 属性可以在
```html
-
+
```
```js
@@ -107,22 +107,22 @@ export default {
setup() {
const value = ref(1);
- let timer;
- const onChange = (newValue) => {
- if (newValue === value.value) {
- return;
- }
-
+ const beforeChange = (value) => {
Toast.loading({ forbidClick: true });
- clearTimeout(this.timer);
- timer = setTimeout(() => {
- Toast.clear();
- value.value = newValue;
- }, 500);
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ Toast.clear();
+ // 在 resolve 函数中返回 true 或 false
+ resolve(true);
+ }, 500);
+ });
};
- return { value };
+ return {
+ value,
+ beforeChange,
+ };
},
};
```
@@ -157,7 +157,7 @@ export default {
| disable-plus | 是否禁用增加按钮 | _boolean_ | `false` |
| disable-minus | 是否禁用减少按钮 | _boolean_ | `false` |
| disable-input | 是否禁用输入框 | _boolean_ | `false` |
-| async-change | 是否开启异步变更,开启后需要手动控制输入值 | _boolean_ | `false` |
+| before-change | 输入值变化前的回调函数,返回 `false` 可阻止输入,支持返回 Promise | _(value) => boolean \| Promise_ | `false` |
| show-plus | 是否显示增加按钮 | _boolean_ | `true` |
| show-minus | 是否显示减少按钮 | _boolean_ | `true` |
| long-press `v2.4.3` | 是否开启长按手势 | _boolean_ | `true` |
diff --git a/src/stepper/demo/index.vue b/src/stepper/demo/index.vue
index ac46f0445..8059dc6e6 100644
--- a/src/stepper/demo/index.vue
+++ b/src/stepper/demo/index.vue
@@ -31,8 +31,8 @@
-
-
+
+
@@ -56,8 +56,8 @@ export default {
range: '限制输入范围',
integer: '限制输入整数',
roundTheme: '圆角风格',
- asyncChange: '异步变更',
customSize: '自定义大小',
+ beforeChange: '异步变更',
disableInput: '禁用输入框',
decimalLength: '固定小数位数',
},
@@ -66,8 +66,8 @@ export default {
range: 'Range',
integer: 'Integer',
roundTheme: 'Round Theme',
- asyncChange: 'Async Change',
customSize: 'Custom Size',
+ beforeChange: 'Before Change',
disableInput: 'Disable Input',
decimalLength: 'Decimal Length',
},
@@ -87,24 +87,20 @@ export default {
disabledInput: 1,
});
- let timer;
- const onChange = (newValue) => {
- if (newValue === state.stepper6) {
- return;
- }
-
+ const beforeChange = () => {
Toast.loading({ forbidClick: true });
- clearTimeout(timer);
- timer = setTimeout(() => {
- state.stepper6 = newValue;
- Toast.clear();
- }, 500);
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ Toast.clear();
+ resolve(true);
+ }, 500);
+ });
};
return {
...toRefs(state),
- onChange,
+ beforeChange,
};
},
};
diff --git a/src/stepper/index.tsx b/src/stepper/index.tsx
index 38d184e70..2ab190e56 100644
--- a/src/stepper/index.tsx
+++ b/src/stepper/index.tsx
@@ -1,4 +1,4 @@
-import { ref, watch, computed } from 'vue';
+import { ref, watch, computed, PropType } from 'vue';
// Utils
import { isNaN } from '../utils/validate/number';
@@ -14,6 +14,7 @@ import {
// Composition
import { useLinkField } from '../composables/use-link-field';
+import { Interceptor, callInterceptor } from '../utils/interceptor';
const [createComponent, bem] = createNamespace('stepper');
@@ -39,11 +40,11 @@ export default createComponent({
modelValue: [Number, String],
inputWidth: [Number, String],
buttonSize: [Number, String],
- asyncChange: Boolean,
placeholder: String,
disablePlus: Boolean,
disableMinus: Boolean,
disableInput: Boolean,
+ beforeChange: Function as PropType,
decimalLength: [Number, String],
name: {
type: [Number, String],
@@ -147,10 +148,15 @@ export default createComponent({
}
};
- const emitChange = (value: string | number) => {
- if (props.asyncChange) {
- emit('update:modelValue', value);
- emit('change', value, { name: props.name });
+ const setValue = (value: string | number) => {
+ if (props.beforeChange) {
+ callInterceptor({
+ args: [value],
+ interceptor: props.beforeChange,
+ done() {
+ current.value = value;
+ },
+ });
} else {
current.value = value;
}
@@ -168,7 +174,7 @@ export default createComponent({
const diff = actionType === 'minus' ? -props.step : +props.step;
const value = format(add(+current.value, diff));
- emitChange(value);
+ setValue(value);
emit(actionType);
};
@@ -185,11 +191,13 @@ export default createComponent({
formatted = `${pair[0]}.${pair[1].slice(0, +decimalLength)}`;
}
- if (!equal(value, formatted)) {
+ if (props.beforeChange) {
+ input.value = String(current.value);
+ } else if (!equal(value, formatted)) {
input.value = formatted;
}
- emitChange(formatted);
+ setValue(formatted);
};
const onFocus = (event: Event) => {
diff --git a/src/utils/interceptor.ts b/src/utils/interceptor.ts
index 916109f1f..be79b952a 100644
--- a/src/utils/interceptor.ts
+++ b/src/utils/interceptor.ts
@@ -1,7 +1,9 @@
import { isPromise, noop } from '.';
+export type Interceptor = (...args: any[]) => Promise | boolean;
+
export function callInterceptor(options: {
- interceptor?: (...args: any[]) => Promise | boolean;
+ interceptor?: Interceptor;
args?: any[];
done: () => void;
canceled?: () => void;