refactor: steps #6406

pull/6423/head
tangjinzhou 2023-04-05 16:28:49 +08:00
parent 9a5cbeee50
commit fbfec0a062
21 changed files with 663 additions and 320 deletions

View File

@ -239,17 +239,43 @@ Components which support rtl direction are listed here, you can toggle the direc
<a-col :span="24"> <a-col :span="24">
<a-divider orientation="left">Steps example</a-divider> <a-divider orientation="left">Steps example</a-divider>
<div> <div>
<a-steps progress-dot :current="state.currentStep"> <a-steps
<a-step title="Finished" description="This is a description." /> progress-dot
<a-step title="In Progress" description="This is a description." /> :current="state.currentStep"
<a-step title="Waiting" description="This is a description." /> :items="[
</a-steps> {
title: 'Finished',
description: 'This is a description.',
},
{
title: 'In Progress',
description: 'This is a description.',
},
{
title: 'Waiting',
description: 'This is a description.',
},
]"
></a-steps>
<br /> <br />
<a-steps :current="state.currentStep" @change="onStepsChange"> <a-steps
<a-step title="Step 1" description="This is a description." /> :current="state.currentStep"
<a-step title="Step 2" description="This is a description." /> :items="[
<a-step title="Step 3" description="This is a description." /> {
</a-steps> title: 'Step 1',
description: 'This is a description.',
},
{
title: 'Step 2',
description: 'This is a description.',
},
{
title: 'Step 3',
description: 'This is a description.',
},
]"
@change="onStepsChange"
></a-steps>
</div> </div>
</a-col> </a-col>
</a-row> </a-row>

View File

@ -198,23 +198,10 @@ Modify global theme color by css variable. Css variable depends on the design, i
<a-pagination show-quick-jumper :default-current="2" :total="500" /> <a-pagination show-quick-jumper :default-current="2" :total="500" />
<!-- Steps --> <!-- Steps -->
<a-steps :current="1" :percent="60"> <a-steps :current="1" :percent="60" :items="stepsItems"></a-steps>
<a-step title="Finished" description="This is a description." />
<a-step
title="In Progress"
sub-title="Left 00:00:08"
description="This is a description."
/>
<a-step title="Waiting" description="This is a description." />
</a-steps>
<!-- Steps - dot --> <!-- Steps - dot -->
<a-steps :current="2" status="error" progress-dot> <a-steps :current="2" status="error" progress-dot :items="stepsItems2"></a-steps>
<a-step title="Finished" description="You can hover on the dot." />
<a-step title="In Progress" description="You can hover on the dot." />
<a-step title="Error" description="You can hover on the dot." />
<a-step title="Waiting" description="You can hover on the dot." />
</a-steps>
<!-- Form - Input --> <!-- Form - Input -->
<a-form> <a-form>
@ -568,6 +555,34 @@ export default defineComponent({
colorState, colorState,
inputProps, inputProps,
selectedKeys: ref(['mail']), selectedKeys: ref(['mail']),
stepsItems: [
{
title: 'Finished',
description: 'This is a description.',
},
{
title: 'In Progress',
description: 'This is a description.',
},
{
title: 'Waiting',
description: 'This is a description.',
},
],
stepsItems2: [
{
title: 'Finished',
description: 'You can hover on the dot.',
},
{
title: 'In Progress',
description: 'You can hover on the dot.',
},
{
title: 'Waiting',
description: 'You can hover on the dot.',
},
],
}; };
}, },
}); });

View File

@ -17,17 +17,42 @@ Setting `v-model` makes Steps clickable.
<template> <template>
<div> <div>
<a-steps v-model:current="current"> <a-steps
<a-step title="Step 1" description="This is a description." /> v-model:current="current"
<a-step title="Step 2" description="This is a description." /> :items="[
<a-step title="Step 3" description="This is a description." /> {
</a-steps> title: 'Step 1',
description,
},
{
title: 'Step 2',
description,
},
{
title: 'Step 3',
description,
},
]"
></a-steps>
<a-divider /> <a-divider />
<a-steps v-model:current="current" direction="vertical"> <a-steps
<a-step title="Step 1" description="This is a description." /> v-model:current="current"
<a-step title="Step 2" description="This is a description." /> direction="vertical"
<a-step title="Step 3" description="This is a description." /> :items="[
</a-steps> {
title: 'Step 1',
description,
},
{
title: 'Step 2',
description,
},
{
title: 'Step 3',
description,
},
]"
></a-steps>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -39,6 +64,7 @@ export default defineComponent({
return { return {
current, current,
description: 'This is a description.',
}; };
}, },
}); });

View File

@ -17,7 +17,27 @@ You can customize the display for Steps with progress dot style.
<template> <template>
<div> <div>
<a-steps :current="1"> <a-steps
v-model:current="current"
:items="[
{
title: 'Finished',
description,
},
{
title: 'In Progress',
description,
},
{
title: 'Waiting',
description,
},
{
title: 'Waiting',
description,
},
]"
>
<template #progressDot="{ index, status, prefixCls }"> <template #progressDot="{ index, status, prefixCls }">
<a-popover> <a-popover>
<template #content> <template #content>
@ -26,10 +46,20 @@ You can customize the display for Steps with progress dot style.
<span :class="`${prefixCls}-icon-dot`" /> <span :class="`${prefixCls}-icon-dot`" />
</a-popover> </a-popover>
</template> </template>
<a-step title="Finished" description="You can hover on the dot." />
<a-step title="In Progress" description="You can hover on the dot." />
<a-step title="Waiting" description="You can hover on the dot." />
<a-step title="Waiting" description="You can hover on the dot." />
</a-steps> </a-steps>
</div> </div>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const current = ref<number>(0);
return {
current,
description: 'This is a description.',
};
},
});
</script>

View File

@ -15,9 +15,36 @@ title:
By using `status` of `Steps`, you can specify the state for current step. By using `status` of `Steps`, you can specify the state for current step.
</docs> </docs>
<template> <template>
<a-steps :current="1" status="error"> <a-steps
<a-step title="Finished" description="This is a description." /> :v-model:current="current"
<a-step title="In Progress" description="This is a description." /> status="error"
<a-step title="Waiting" description="This is a description." /> :items="[
</a-steps> {
title: 'Finished',
description,
},
{
title: 'In Process',
description,
},
{
title: 'Waiting',
description,
},
]"
></a-steps>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const current = ref<number>(0);
return {
current,
description: 'This is a description.',
};
},
});
</script>

View File

@ -15,44 +15,47 @@ title:
You can use your own custom icons by setting the property `icon` for `Steps.Step`. You can use your own custom icons by setting the property `icon` for `Steps.Step`.
</docs> </docs>
<template> <template>
<a-steps> <a-steps :items="items"></a-steps>
<a-step status="finish" title="Login">
<template #icon>
<user-outlined />
</template>
</a-step>
<a-step status="finish" title="Verification">
<template #icon>
<solution-outlined />
</template>
</a-step>
<a-step status="process" title="Pay">
<template #icon>
<loading-outlined />
</template>
</a-step>
<a-step status="wait" title="Done">
<template #icon>
<smile-outlined />
</template>
</a-step>
</a-steps>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent, ref, h } from 'vue';
import { import {
UserOutlined, UserOutlined,
SolutionOutlined, SolutionOutlined,
LoadingOutlined, LoadingOutlined,
SmileOutlined, SmileOutlined,
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import { StepProps } from 'ant-design-vue';
export default defineComponent({ export default defineComponent({
components: { setup() {
UserOutlined, const current = ref<number>(0);
SolutionOutlined,
LoadingOutlined, return {
SmileOutlined, current,
items: [
{
title: 'Login',
status: 'finish',
icon: h(UserOutlined),
},
{
title: 'Verification',
status: 'finish',
icon: h(SolutionOutlined),
},
{
title: 'Pay',
status: 'process',
icon: h(LoadingOutlined),
},
{
title: 'Done',
status: 'wait',
icon: h(SmileOutlined),
},
] as StepProps[],
};
}, },
}); });
</script> </script>

View File

@ -43,15 +43,8 @@ Inline type steps, suitable for displaying the process and current state of the
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { List, Steps, Avatar } from 'ant-design-vue';
export default defineComponent({ export default defineComponent({
components: {
[List.name]: List,
[Steps.name]: Steps,
[Avatar.name]: Avatar,
},
setup() { setup() {
const data = [ const data = [
{ {

View File

@ -17,38 +17,80 @@ Navigation steps.
<template> <template>
<div> <div>
<a-steps v-model:current="current" type="navigation" size="small" :style="stepStyle"> <a-steps
<a-step v-model:current="current"
title="Step 1" type="navigation"
sub-title="00:00:05" size="small"
status="finish" :style="stepStyle"
description="This is a description." :items="[
/> {
<a-step title: 'Step 1',
title="Step 2" subTitle: '00:00:05',
sub-title="00:01:02" status: 'finish',
status="process" description: 'This is a description.',
description="This is a description." },
/> {
<a-step title: 'Step 2',
title="Step 3" subTitle: '00:01:02',
sub-title="waiting for longlong time" status: 'process',
status="wait" description: 'This is a description.',
description="This is a description." },
/> {
</a-steps> title: 'Step 3',
<a-steps v-model:current="current" type="navigation" :style="stepStyle"> subTitle: 'waiting for longlong time',
<a-step status="finish" title="Step 1" /> status: 'wait',
<a-step status="process" title="Step 2" /> description: 'This is a description.',
<a-step status="wait" title="Step 3" /> },
<a-step status="wait" title="Step 4" /> ]"
</a-steps> ></a-steps>
<a-steps v-model:current="current" type="navigation" size="small" :style="stepStyle"> <a-steps
<a-step status="finish" title="finish 1" /> v-model:current="current"
<a-step status="finish" title="finish 2" /> type="navigation"
<a-step status="process" title="current process" /> :style="stepStyle"
<a-step status="wait" title="wait" disabled /> :items="[
</a-steps> {
status: 'finish',
title: 'Step 1',
},
{
status: 'process',
title: 'Step 2',
},
{
status: 'wait',
title: 'Step 3',
},
{
status: 'wait',
title: 'Step 4',
},
]"
></a-steps>
<a-steps
v-model:current="current"
type="navigation"
size="small"
:style="stepStyle"
:items="[
{
status: 'finish',
title: 'finish 1',
},
{
status: 'finish',
title: 'finish 2',
},
{
status: 'process',
title: 'current process',
},
{
status: 'wait',
title: 'wait',
disabled: true,
},
]"
></a-steps>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -17,18 +17,51 @@ Steps with progress dot style.
<template> <template>
<div> <div>
<a-steps progress-dot :current="1"> <a-steps
<a-step title="Finished" description="This is a description." /> progress-dot
<a-step title="In Progress" description="This is a description." /> :current="1"
<a-step title="Waiting" description="This is a description." /> :items="[
</a-steps> {
title: 'Finished',
description: 'This is a description.',
},
{
title: 'In Progress',
description: 'This is a description.',
},
{
title: 'Waiting',
description: 'This is a description.',
},
]"
></a-steps>
<a-divider /> <a-divider />
<a-steps progress-dot :current="1" direction="vertical"> <a-steps
<a-step title="Finished" description="This is a description. This is a description." /> progress-dot
<a-step title="Finished" description="This is a description. This is a description." /> :current="1"
<a-step title="In Progress" description="This is a description. This is a description." /> direction="vertical"
<a-step title="Waiting" description="This is a description." /> :items="[
<a-step title="Waiting" description="This is a description." /> {
</a-steps> title: 'Finished',
description: 'This is a description. This is a description.',
},
{
title: 'Finished',
description: 'This is a description. This is a description.',
},
{
title: 'In Progress',
description: 'This is a description. This is a description.',
},
{
title: 'Waiting',
description: 'This is a description.',
},
{
title: 'Waiting',
description: 'This is a description.',
},
]"
></a-steps>
</div> </div>
</template> </template>

View File

@ -17,14 +17,57 @@ Steps with progress.
</docs> </docs>
<template> <template>
<a-steps :percent="60" :current="1"> <a-steps
<a-step title="Finished" description="This is a description." /> :percent="60"
<a-step title="In Progress" sub-title="Left 00:00:08" description="This is a description." /> :v-model:current="current"
<a-step title="Waiting" description="This is a description." /> :items="[
</a-steps> {
<a-steps :percent="60" :current="1" size="small"> title: 'Finished',
<a-step title="Finished" description="This is a description." /> description,
<a-step title="In Progress" sub-title="Left 00:00:08" description="This is a description." /> },
<a-step title="Waiting" description="This is a description." /> {
</a-steps> title: 'In Progress',
subTitle: 'Left 00:00:08',
description,
},
{
title: 'Waiting',
description,
},
]"
></a-steps>
<a-steps
:percent="60"
:current="1"
size="small"
:items="[
{
title: 'Finished',
description,
},
{
title: 'In Progress',
subTitle: 'Left 00:00:08',
description,
},
{
title: 'Waiting',
description,
},
]"
></a-steps>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const current = ref<number>(0);
return {
current,
description: 'This is a description.',
};
},
});
</script>

View File

@ -15,15 +15,36 @@ title:
The most basic step bar. The most basic step bar.
</docs> </docs>
<template> <template>
<a-steps :current="1"> <a-steps
<a-step> :current="1"
<!-- <span slot="title">Finished</span> --> :items="[
<template #title>Finished</template> {
<template #description> title: 'Finished',
<span>This is a description.</span> description,
</template> },
</a-step> {
<a-step title="In Progress" sub-title="Left 00:00:08" description="This is a description." /> title: 'In Progress',
<a-step title="Waiting" description="This is a description." /> description,
</a-steps> subTitle: 'Left 00:00:08',
},
{
title: 'Waiting',
description,
},
]"
></a-steps>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const current = ref<number>(0);
return {
current,
description: 'This is a description.',
};
},
});
</script>

View File

@ -15,9 +15,33 @@ title:
By setting like this: `<Steps size="small">`, you can get a mini version. By setting like this: `<Steps size="small">`, you can get a mini version.
</docs> </docs>
<template> <template>
<a-steps :current="1" size="small"> <a-steps
<a-step title="Finished" /> :current="1"
<a-step title="In Progress" /> size="small"
<a-step title="Waiting" /> :items="[
</a-steps> {
title: 'Finished',
},
{
title: 'In Progress',
},
{
title: 'Waiting',
},
]"
></a-steps>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const current = ref<number>(0);
return {
current,
description: 'This is a description.',
};
},
});
</script>

View File

@ -16,9 +16,7 @@ Cooperate with the content and buttons, to represent the progress of a process.
</docs> </docs>
<template> <template>
<div> <div>
<a-steps :current="current"> <a-steps :current="current" :items="items"></a-steps>
<a-step v-for="item in steps" :key="item.title" :title="item.title" />
</a-steps>
<div class="steps-content"> <div class="steps-content">
{{ steps[current].content }} {{ steps[current].content }}
</div> </div>
@ -48,23 +46,26 @@ export default defineComponent({
const prev = () => { const prev = () => {
current.value--; current.value--;
}; };
const steps = [
{
title: 'First',
content: 'First-content',
},
{
title: 'Second',
content: 'Second-content',
},
{
title: 'Last',
content: 'Last-content',
},
];
const items = steps.map(item => ({ key: item.title, title: item.title }));
return { return {
message, message,
current, current,
steps: [ steps,
{ items,
title: 'First',
content: 'First-content',
},
{
title: 'Second',
content: 'Second-content',
},
{
title: 'Last',
content: 'Last-content',
},
],
next, next,
prev, prev,
}; };

View File

@ -15,9 +15,34 @@ title:
A simple mini version step bar in the vertical direction. A simple mini version step bar in the vertical direction.
</docs> </docs>
<template> <template>
<a-steps direction="vertical" size="small" :current="1"> <a-steps
<a-step title="Finished" description="This is a description." /> direction="vertical"
<a-step title="In Progress" description="This is a description." /> size="small"
<a-step title="Waiting" description="This is a description." /> :current="1"
</a-steps> :items="[
{ title: 'Finished', description },
{
title: 'In Progress',
description,
},
{
title: 'Waiting',
description,
},
]"
></a-steps>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const current = ref<number>(0);
return {
current,
description: 'This is a description.',
};
},
});
</script>

View File

@ -16,9 +16,36 @@ A simple step bar in the vertical direction.
</docs> </docs>
<template> <template>
<a-steps direction="vertical" :current="1"> <a-steps
<a-step title="Finished" description="This is a description." /> direction="vertical"
<a-step title="In Progress" description="This is a description." /> :current="1"
<a-step title="Waiting" description="This is a description." /> :items="[
</a-steps> {
title: 'Finished',
description,
},
{
title: 'In Progress',
description,
},
{
title: 'Waiting',
description,
},
]"
></a-steps>
</template> </template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const current = ref<number>(0);
return {
current,
description: 'This is a description.',
};
},
});
</script>

View File

@ -29,23 +29,21 @@ The whole of the step bar.
| type | Type of steps, can be set to one of the following values: `default`, `navigation` | string | `default` | 1.5.0 | | type | Type of steps, can be set to one of the following values: `default`, `navigation` | string | `default` | 1.5.0 |
| items | StepItem content | [StepItem](#stepsstep) | [] | | | items | StepItem content | [StepItem](#stepsstep) | [] | |
### `type="inline"` (4.0+)
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| current | To set the current step, counting from 0. You can overwrite this state by using `status` of `Step` | number | 0 | |
| initial | Set the initial step, counting from 0 | number | 0 | |
| status | To specify the status of current step, can be set to one of the following values: `wait` `process` `finish` `error` | string | `process` | |
| items | StepItem content. not supported: `icon` `subtitle` | [StepItem](#stepsstep) | [] | |
#### Steps Events #### Steps Events
| Events Name | Description | Arguments | Version | | | Events Name | Description | Arguments | Version | |
| ----------- | ---------------------------- | ----------------- | ------- | ----- | | ----------- | ---------------------------- | ----------------- | ------- | ----- |
| change | Trigger when Step is changed | (current) => void | - | 1.5.0 | | change | Trigger when Step is changed | (current) => void | - | 1.5.0 |
### `type="inline"`
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| className | Additional class to Steps | string | - | |
| current | To set the current step, counting from 0. You can overwrite this state by using `status` of `Step` | number | 0 | |
| initial | Set the initial step, counting from 0 | number | 0 | |
| status | To specify the status of current step, can be set to one of the following values: `wait` `process` `finish` `error` | string | `process` | |
| onChange | Trigger when Step is changed | (current) => void | - | |
| items | StepItem content. not supported: `icon` `subtitle` | [StepItem](#stepsstep) | [] | 4.24.0 |
### Steps.Step ### Steps.Step
A single step in the step bar. A single step in the step bar.

View File

@ -2,8 +2,8 @@ import type { App, ExtractPropTypes } from 'vue';
import { computed, defineComponent } from 'vue'; import { computed, defineComponent } from 'vue';
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined'; import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined'; import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
import PropTypes from '../_util/vue-types';
import type { VueNode } from '../_util/type'; import type { VueNode } from '../_util/type';
import { anyType, booleanType, stringType, functionType, someType, arrayType } from '../_util/type';
import initDefaultProps from '../_util/props-util/initDefaultProps'; import initDefaultProps from '../_util/props-util/initDefaultProps';
import VcSteps, { Step as VcStep } from '../vc-steps'; import VcSteps, { Step as VcStep } from '../vc-steps';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
@ -13,9 +13,8 @@ import Progress from '../progress';
import omit from '../_util/omit'; import omit from '../_util/omit';
import Tooltip from '../tooltip'; import Tooltip from '../tooltip';
import { VcStepProps } from '../vc-steps/Step'; import { VcStepProps } from '../vc-steps/Step';
import type { ProgressDotRender } from '../vc-steps/Steps'; import type { Status, ProgressDotRender } from '../vc-steps/interface';
import type { MouseEventHandler } from '../_util/EventInterface'; import type { MouseEventHandler } from '../_util/EventInterface';
import { booleanType, stringType, functionType, someType, arrayType } from '../_util/type';
// CSSINJS // CSSINJS
import useStyle from './style'; import useStyle from './style';
@ -29,7 +28,7 @@ export const stepsProps = () => ({
responsive: booleanType(), responsive: booleanType(),
items: arrayType<StepProps[]>(), items: arrayType<StepProps[]>(),
labelPlacement: stringType<'horizontal' | 'vertical'>(), labelPlacement: stringType<'horizontal' | 'vertical'>(),
status: stringType<'wait' | 'process' | 'finish' | 'error'>(), status: stringType<Status>(),
size: stringType<'default' | 'small'>(), size: stringType<'default' | 'small'>(),
direction: stringType<'horizontal' | 'vertical'>(), direction: stringType<'horizontal' | 'vertical'>(),
progressDot: someType<boolean | ProgressDotRender>([Boolean, Function]), progressDot: someType<boolean | ProgressDotRender>([Boolean, Function]),
@ -39,12 +38,12 @@ export const stepsProps = () => ({
}); });
export const stepProps = () => ({ export const stepProps = () => ({
description: PropTypes.any, description: anyType(),
icon: PropTypes.any, icon: anyType(),
status: stringType<'wait' | 'process' | 'finish' | 'error'>(), status: stringType<Status>(),
disabled: booleanType(), disabled: booleanType(),
title: PropTypes.any, title: anyType(),
subTitle: PropTypes.any, subTitle: anyType(),
onClick: functionType<MouseEventHandler>(), onClick: functionType<MouseEventHandler>(),
}); });
@ -65,7 +64,6 @@ const Steps = defineComponent({
// emits: ['update:current', 'change'], // emits: ['update:current', 'change'],
setup(props, { attrs, slots, emit }) { setup(props, { attrs, slots, emit }) {
const { prefixCls, direction: rtlDirection, configProvider } = useConfigInject('steps', props); const { prefixCls, direction: rtlDirection, configProvider } = useConfigInject('steps', props);
const mergedItems = computed(() => props.items);
// style // style
const [wrapSSR, hashId] = useStyle(prefixCls); const [wrapSSR, hashId] = useStyle(prefixCls);
@ -130,7 +128,7 @@ const Steps = defineComponent({
icons={icons.value} icons={icons.value}
{...attrs} {...attrs}
{...omit(props, ['percent', 'responsive'])} {...omit(props, ['percent', 'responsive'])}
items={mergedItems.value} items={props.items}
direction={direction.value} direction={direction.value}
prefixCls={prefixCls.value} prefixCls={prefixCls.value}
iconPrefix={iconPrefix.value} iconPrefix={iconPrefix.value}

View File

@ -34,23 +34,21 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*cFsBQLA0b7UAAA
| type | 步骤条类型,有 `default``navigation` 两种 | string | `default` | 1.5.0 | | type | 步骤条类型,有 `default``navigation` 两种 | string | `default` | 1.5.0 |
| items | 配置选项卡内容 | [StepItem](#stepsstep)[] | [] | | | items | 配置选项卡内容 | [StepItem](#stepsstep)[] | [] | |
### `type="inline"` (4.0+)
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| current | 指定当前步骤,从 0 开始记数。在子 Step 元素中,可以通过 `status` 属性覆盖状态 | number | 0 | |
| initial | 起始序号,从 0 开始记数 | number | 0 | |
| status | 指定当前步骤的状态,可选 `wait` `process` `finish` `error` | string | `process` | |
| items | 配置选项卡内容,不支持 `icon` `subtitle` | [StepItem](#stepsstep) | [] | |
#### Steps 事件 #### Steps 事件
| 事件名称 | 说明 | 回调参数 | 版本 | | | 事件名称 | 说明 | 回调参数 | 版本 | |
| -------- | ------------------ | ----------------- | ---- | ----- | | -------- | ------------------ | ----------------- | ---- | ----- |
| change | 点击切换步骤时触发 | (current) => void | - | 1.5.0 | | change | 点击切换步骤时触发 | (current) => void | - | 1.5.0 |
### `type="inline"`
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| className | 步骤条类名 | string | - | |
| current | 指定当前步骤,从 0 开始记数。在子 Step 元素中,可以通过 `status` 属性覆盖状态 | number | 0 | |
| initial | 起始序号,从 0 开始记数 | number | 0 | |
| status | 指定当前步骤的状态,可选 `wait` `process` `finish` `error` | string | `process` | |
| onChange | 点击切换步骤时触发 | (current) => void | - | |
| items | 配置选项卡内容,不支持 `icon` `subtitle` | [StepItem](#stepsstep) | [] | 4.24.0 |
### Steps.Step ### Steps.Step
步骤条内的每一个步骤。 步骤条内的每一个步骤。

View File

@ -1,27 +1,28 @@
import PropTypes, { withUndefined } from '../_util/vue-types'; import PropTypes, { withUndefined } from '../_util/vue-types';
import type { CSSProperties, PropType } from 'vue'; import type { CSSProperties, ExtractPropTypes } from 'vue';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import type { EventHandler } from '../_util/EventInterface'; import type { EventHandler } from '../_util/EventInterface';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
import warning from '../_util/warning';
import type { VueNode } from '../_util/type';
import { stringType, functionType } from '../_util/type';
import type { StepIconRender, Status } from './interface';
function isString(str: any): str is string { function isString(str: any): str is string {
return typeof str === 'string'; return typeof str === 'string';
} }
function noop() {} function noop() {}
export const VcStepProps = () => ({ export const VcStepProps = () => ({
class: PropTypes.string,
prefixCls: String, prefixCls: String,
wrapperStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
itemWidth: String, itemWidth: String,
active: { type: Boolean, default: undefined }, active: { type: Boolean, default: undefined },
disabled: { type: Boolean, default: undefined }, disabled: { type: Boolean, default: undefined },
status: String, status: stringType<Status>(),
iconPrefix: String, iconPrefix: String,
icon: PropTypes.any, icon: PropTypes.any,
adjustMarginRight: String, adjustMarginRight: String,
stepNumber: Number, stepNumber: Number,
stepIndex: Number, stepIndex: Number,
style: PropTypes.style,
description: PropTypes.any, description: PropTypes.any,
title: PropTypes.any, title: PropTypes.any,
subTitle: PropTypes.any, subTitle: PropTypes.any,
@ -31,22 +32,30 @@ export const VcStepProps = () => ({
finish: PropTypes.any, finish: PropTypes.any,
error: PropTypes.any, error: PropTypes.any,
}).loose, }).loose,
onClick: Function, onClick: functionType(),
onStepClick: Function, onStepClick: functionType<(next: number) => void>(),
stepIcon: Function, stepIcon: functionType<StepIconRender>(),
itemRender: functionType<(stepItem: VueNode) => VueNode>(),
}); });
export type VCStepProps = Partial<ExtractPropTypes<ReturnType<typeof VcStepProps>>>;
export default defineComponent({ export default defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
name: 'Step', name: 'Step',
props: VcStepProps(), props: VcStepProps(),
slots: ['title', 'subTitle', 'description', 'tailContent', 'stepIcon', 'progressDot'], slots: ['title', 'subTitle', 'description', 'tailContent', 'stepIcon', 'progressDot'],
emits: ['click', 'stepClick'], setup(props, { slots, emit, attrs }) {
setup(props, { slots, emit }) {
const onItemClick: EventHandler = e => { const onItemClick: EventHandler = e => {
emit('click', e); emit('click', e);
emit('stepClick', props.stepIndex); emit('stepClick', props.stepIndex);
}; };
if (attrs.__legacy !== false) {
warning(
false,
'Steps',
'Step is deprecated, and not support inline type. Please use `items` directly. ',
);
}
const renderIconNode = ({ icon, title, description }) => { const renderIconNode = ({ icon, title, description }) => {
const { const {
prefixCls, prefixCls,
@ -113,7 +122,6 @@ export default defineComponent({
const { const {
prefixCls, prefixCls,
itemWidth, itemWidth,
style,
active, active,
status = 'wait', status = 'wait',
tailContent, tailContent,
@ -127,20 +135,15 @@ export default defineComponent({
onStepClick, onStepClick,
} = props; } = props;
const mergedStatus = status || 'wait'; const mergedStatus = status || 'wait';
const classString = classNames( const classString = classNames(`${prefixCls}-item`, `${prefixCls}-item-${mergedStatus}`, {
`${prefixCls}-item`, [`${prefixCls}-item-custom`]: icon,
`${prefixCls}-item-${mergedStatus}`, [`${prefixCls}-item-active`]: active,
props.class, [`${prefixCls}-item-disabled`]: disabled === true,
{ });
[`${prefixCls}-item-custom`]: icon,
[`${prefixCls}-item-active`]: active,
[`${prefixCls}-item-disabled`]: disabled === true,
},
);
const stepProps = { const stepProps = {
class: classString, class: classString,
}; };
const stepItemStyle: CSSProperties = { ...style }; const stepItemStyle: CSSProperties = {};
if (itemWidth) { if (itemWidth) {
stepItemStyle.width = itemWidth; stepItemStyle.width = itemWidth;
} }
@ -161,8 +164,8 @@ export default defineComponent({
accessibilityProps.tabindex = 0; accessibilityProps.tabindex = 0;
accessibilityProps.onClick = onItemClick; accessibilityProps.onClick = onItemClick;
} }
return ( const stepNode = (
<div {...stepProps} style={stepItemStyle}> <div {...stepProps} style={[attrs.style as CSSProperties, stepItemStyle]}>
<div {...accessibilityProps} class={`${prefixCls}-item-container`}> <div {...accessibilityProps} class={`${prefixCls}-item-container`}>
<div class={`${prefixCls}-item-tail`}>{tailContent}</div> <div class={`${prefixCls}-item-tail`}>{tailContent}</div>
<div class={`${prefixCls}-item-icon`}> <div class={`${prefixCls}-item-icon`}>
@ -185,6 +188,10 @@ export default defineComponent({
</div> </div>
</div> </div>
); );
if (props.itemRender) {
return props.itemRender(stepNode);
}
return stepNode;
}; };
}, },
}); });

View File

@ -1,25 +1,13 @@
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
import type { VCStepProps } from './Step';
import Step from './Step'; import Step from './Step';
import { cloneElement } from '../_util/vnode'; import type { VueNode } from '../_util/type';
import { functionType, stringType } from '../_util/type';
import { filterEmpty } from '../_util/props-util'; import { filterEmpty } from '../_util/props-util';
export type Status = 'error' | 'process' | 'finish' | 'wait'; import { cloneElement } from '../_util/vnode';
export type StepIconRender = (info: { import type { Status, StepIconRender } from './interface';
index: number;
status: Status;
title: any;
description: any;
node: any;
}) => any;
export type ProgressDotRender = (info: {
iconDot: any;
index: number;
status: Status;
title: any;
description: any;
}) => any;
export default defineComponent({ export default defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
@ -30,7 +18,7 @@ export default defineComponent({
iconPrefix: PropTypes.string.def('vc'), iconPrefix: PropTypes.string.def('vc'),
direction: PropTypes.string.def('horizontal'), direction: PropTypes.string.def('horizontal'),
labelPlacement: PropTypes.string.def('horizontal'), labelPlacement: PropTypes.string.def('horizontal'),
status: PropTypes.string.def('process'), status: stringType<Status>('process'),
size: PropTypes.string.def(''), size: PropTypes.string.def(''),
progressDot: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func]).def(undefined), progressDot: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func]).def(undefined),
initial: PropTypes.number.def(0), initial: PropTypes.number.def(0),
@ -40,25 +28,85 @@ export default defineComponent({
finish: PropTypes.any, finish: PropTypes.any,
error: PropTypes.any, error: PropTypes.any,
}).loose, }).loose,
style: PropTypes.style, stepIcon: functionType<StepIconRender>(),
stepIcon: Function,
isInline: PropTypes.looseBool, isInline: PropTypes.looseBool,
itemRender: Function, itemRender: functionType<(item: Record<string, any>, stepItem: VueNode) => VueNode>(),
}, },
slots: ['stepIcon', 'progressDot'], slots: ['stepIcon', 'progressDot'],
emits: ['change'], emits: ['change'],
setup(props, { slots, emit }) { setup(props, { slots, emit }) {
const onStepClick = next => { const onStepClick = (next: number) => {
const { current } = props; const { current } = props;
if (current !== next) { if (current !== next) {
emit('change', next); emit('change', next);
} }
}; };
const renderStep = (item: VCStepProps, index: number, legacyRender?: any) => {
const {
prefixCls,
iconPrefix,
status,
current,
initial,
icons,
stepIcon = slots.stepIcon,
isInline,
itemRender,
progressDot = slots.progressDot,
} = props;
const mergedProgressDot = isInline || progressDot;
const mergedItem = { ...item, class: '' };
const stepNumber = initial + index;
const commonProps = {
active: stepNumber === current,
stepNumber: stepNumber + 1,
stepIndex: stepNumber,
key: stepNumber,
prefixCls,
iconPrefix,
progressDot: mergedProgressDot,
stepIcon,
icons,
onStepClick,
};
// fix tail color
if (status === 'error' && index === current - 1) {
mergedItem.class = `${prefixCls}-next-error`;
}
if (!mergedItem.status) {
if (stepNumber === current) {
mergedItem.status = status;
} else if (stepNumber < current) {
mergedItem.status = 'finish';
} else {
mergedItem.status = 'wait';
}
}
if (isInline) {
mergedItem.icon = undefined;
mergedItem.subTitle = undefined;
}
if (legacyRender) {
return legacyRender({ ...mergedItem, ...commonProps });
}
if (itemRender) {
mergedItem.itemRender = stepItem => itemRender(mergedItem, stepItem);
}
return <Step {...mergedItem} {...commonProps} __legacy={false} />;
};
const renderStepWithNode = (node: any, index: number) => {
return renderStep({ ...node.props }, index, stepProps => {
const stepNode = cloneElement(node, stepProps);
return stepNode;
});
};
return () => { return () => {
const { const {
prefixCls, prefixCls,
direction, direction,
style = {},
type, type,
labelPlacement, labelPlacement,
iconPrefix, iconPrefix,
@ -68,7 +116,6 @@ export default defineComponent({
progressDot = slots.progressDot, progressDot = slots.progressDot,
initial, initial,
icons, icons,
stepIcon = slots.stepIcon,
items, items,
isInline, isInline,
itemRender, itemRender,
@ -87,68 +134,11 @@ export default defineComponent({
[`${prefixCls}-navigation`]: isNav, [`${prefixCls}-navigation`]: isNav,
[`${prefixCls}-inline`]: isInline, [`${prefixCls}-inline`]: isInline,
}); });
const renderStep = (props, index, render) => {
const { prefixCls: pre = prefixCls, ...restProps } = props || {};
const stepNumber = initial + index;
const stepProps = {
...restProps,
stepNumber: stepNumber + 1,
stepIndex: stepNumber,
key: stepNumber,
prefixCls: pre,
iconPrefix,
progressDot: mergedProgressDot,
icons,
stepIcon,
onStepClick,
active: stepNumber === current,
};
// fix tail color
if (status === 'error' && index === current - 1) {
stepProps.class = `${prefixCls}-next-error`;
}
if (!restProps.status) {
if (stepNumber === current) {
stepProps.status = status;
} else if (stepNumber < current) {
stepProps.status = 'finish';
} else {
stepProps.status = 'wait';
}
}
if (isInline) {
stepProps.icon = undefined;
stepProps.subTitle = undefined;
}
stepProps.active = stepNumber === current;
return render(stepProps);
};
const renderStepWithNode = (node, index) => {
return renderStep({ ...node.props }, index, stepProps => {
const stepNode = cloneElement(node, stepProps);
if (itemRender) {
return itemRender(stepProps, stepNode);
}
return stepNode;
});
};
const renderStepWithItem = (item, index) => {
return renderStep(item, index, stepProps => {
const stepNode = <Step {...stepProps} />;
if (itemRender) {
return itemRender(stepProps, stepNode);
}
return stepNode;
});
};
return ( return (
<div class={classString} style={style} {...restProps}> <div class={classString} {...restProps}>
{items.length {items.filter(item => item).map((item, index) => renderStep(item, index))}
? items.map(renderStepWithItem) {filterEmpty(slots.default?.()).map(renderStepWithNode)}
: filterEmpty(slots.default?.()).map(renderStepWithNode)}
</div> </div>
); );
}; };

View File

@ -0,0 +1,16 @@
export type Status = 'error' | 'process' | 'finish' | 'wait';
export type StepIconRender = (info: {
index: number;
status: Status;
title: any;
description: any;
node: any;
}) => any;
export type ProgressDotRender = (info: {
iconDot: any;
index: number;
status: Status;
title: any;
description: any;
}) => any;