| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- <template>
- <view
- :style="{
- ...innerStyle,
- ...(context.direction.value === 'vertical' ?
- themeStyles.itemVertical.value :
- themeStyles.itemHorizontal.value) ,
- flexBasis: context.direction.value === 'horizontal' ?
- themeContext.resolveSize(context.lineItemWidth.value) :
- undefined,
- width: context.direction.value === 'horizontal' ?
- themeContext.resolveSize(context.lineItemWidth.value) :
- undefined,
- }"
- >
- <view
- :style="{
- ...themeStyles.iconContainer.value,
- width: themeContext.resolveSize(iconConSize),
- height: themeContext.resolveSize(iconSize)
- }"
- >
- <StepItemInternalDotNumberIcon
- v-if="useDefaultIcon && inactiveIcon === '__default_number'"
- :index="index + 1"
- :size="(iconProps.size as number)"
- :color="state === 'inactive' ? context.inactiveColor.value : context.activeColor.value"
- />
- <StepItemInternalDotIcon
- v-else-if="useDefaultIcon && inactiveIcon === '__default_dot'"
- :size="(iconProps.size as number)"
- :color="state === 'inactive' ? context.inactiveColor.value : context.activeColor.value" />
- <Icon
- v-else
- :color="state === 'active' || state === 'finish' ? context.activeColor.value : context.inactiveColor.value"
- :icon="state === 'active' ? (activeIcon || inactiveIcon) : (state === 'finish' ? finishIcon : inactiveIcon)"
- v-bind="iconProps"
- />
- </View>
- <view :style="themeStyles.content.value">
- <text
- :style="{
- color: context.textColor.value,
- ...themeStyles.text.value,
- ...textStyle,
- }"
- >
- {{ text }}
- </text>
- <slot name="extra">
- <text v-if="extra" :style="{
- color: context.textColor.value,
- ...themeStyles.text.value,
- ...textStyle,
- }">
- {{ extra }}
- </text>
- </slot>
- </view>
- <!-- 渲染垂直线段 -->
- <view
- v-if="context.direction.value === 'vertical' && !isLast"
- :style="{
- position: 'absolute',
- left: themeContext.resolveSize(iconConSize / 2 - context.lineWidth.value! / 2),
- top: themeContext.resolveSize(iconConSize - 2),
- bottom: themeContext.resolveSize(-iconConSize / 2),
- backgroundColor: themeContext.resolveThemeColor(state === 'finish' ? context.activeColor.value : context.inactiveColor.value),
- width: themeContext.resolveSize(context.lineWidth.value!),
- }"
- />
- </view>
- <!-- 水平条目之间还需要渲染线段 -->
- <view
- v-if="context.direction.value === 'horizontal' && !isLast"
- :style="{
- position: 'absolute',
- left: themeContext.resolveSize((index + 1) * context.lineItemWidth.value! - context.lineItemWidth.value! / 4),
- top: themeContext.resolveSize(context.lineOffset.value!),
- backgroundColor: themeContext.resolveThemeColor(context.activeIndex.value > index ? context.activeColor.value : context.inactiveColor.value),
- height: themeContext.resolveSize(context.lineWidth.value!),
- width: themeContext.resolveSize(context.lineItemWidth.value! / 2),
- }"
- />
- </template>
- <script setup lang="ts">
- import { computed, inject, onMounted, onUpdated, ref } from 'vue';
- import { propGetThemeVar, useTheme, type TextStyle, type ViewStyle } from '../theme/ThemeDefine';
- import { DynamicSize } from '../theme/ThemeTools';
- import type { StepContext } from './Step.vue';
- import type { IconProps } from '../basic/Icon.vue';
- import Icon from '../basic/Icon.vue';
- import StepItemInternalDotIcon from './step/StepItemInternalDotIcon.vue';
- import StepItemInternalDotNumberIcon from './step/StepItemInternalDotNumberIcon.vue';
- const themeContext = useTheme();
- export type StepItemState = 'inactive'|'active'|'finish';
- export interface StepItemProps {
- /**
- * 自定义激活状态图标。为空时尝试使用 inactiveIcon 的值。
- */
- activeIcon?: string,
- /**
- * 自定义未激活状态图标。有2个特殊值 `__default_number` 表示一个圆圈中间一个当前步骤的序号;`__default_dot` 表示一个圆圈。
- * @default 横向默认是 '__default_number',竖向默认是 '__default_dot'
- */
- inactiveIcon?: string,
- /**
- * 自定义已完成步骤对应的底部图标,优先级高于 `inactiveIcon`
- * @default 'success-filling'
- */
- finishIcon?: string,
- /**
- * 图标的附加属性
- * @default { size: 48 }
- */
- iconProps?: IconProps;
- /**
- * 步骤的文字自定义样式
- */
- textStyle?: TextStyle,
- /**
- * 步骤的自定义样式
- */
- innerStyle?: ViewStyle,
- /**
- * 当前步骤的文字
- */
- text?: string;
- /**
- * 垂直模式下,允许你渲染附加内容
- */
- extra?: string;
- }
- const context = inject('StepContext') as StepContext;
- const emit = defineEmits([ 'click' ]);
- const props = withDefaults(defineProps<StepItemProps>(), {
- iconProps: () => ({ size: propGetThemeVar('StepItemIconDefaultSize', 48) }),
- activeIcon: () => propGetThemeVar('StepItemActiveIcon', ''),
- finishIcon: () => propGetThemeVar('StepItemFinishIcon', 'success-filling'),
- inactiveIcon: () => (inject('StepContext') as StepContext).direction.value === 'horizontal' ?
- '__default_number' : '__default_dot',
- });
- const index = computed(() => context.getPosition());
- const useDefaultIcon = computed(() => (state.value === 'inactive' || (state.value === 'active' && !props.activeIcon)));
- const iconConSize = computed(() => props.iconProps.size as number + 0);
- const iconSize = computed(() => props.iconProps.size as number);
- const state = computed(() => context.activeIndex.value === index.value ? 'active' : (context.activeIndex.value > index.value ? 'finish' : 'inactive'));
- const isLast = ref(false);
- function updateWithCount() {
- isLast.value = index.value >= context.getLength() - 1;
- }
- onUpdated(updateWithCount);
- onMounted(updateWithCount);
- const themeStyles = themeContext.useThemeStyles({
- itemVertical: {
- display: 'flex',
- position: 'relative',
- flexDirection: 'row',
- justifyContent: 'flex-start',
- alignItems: 'flex-start',
- marginVertical: DynamicSize('StepItemMarginVertical', 10),
- },
- itemHorizontal: {
- flex: '0 0 0%',
- display: 'flex',
- position: 'relative',
- flexDirection: 'column',
- justifyContent: 'center',
- alignItems: 'center',
- },
- text: {
- fontSize: DynamicSize('StepItemTextFontSize', 26),
- },
- content: {
- fontSize: DynamicSize('StepItemContentFontSize', 26),
- marginTop: DynamicSize('StepItemContentMarginTop', 6),
- marginLeft: DynamicSize('StepItemContentMarginLeft', 6),
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
- alignItems: 'flex-start',
- },
- iconContainer: {
- display: 'flex',
- flexDirection: 'row',
- justifyContent: 'center',
- alignItems: 'center',
- },
- });
- </script>
|