<template> <view class="tn-steps-class tn-steps" :style="{ flexDirection: direction }" > <view v-for="(item, index) in list" :key="index" class="tn-steps__item" :class="[`tn-steps__item--${direction}`]" @tap="clickStepItem(index)" > <!-- 数值模式 --> <view v-if="mode === 'number'" class="tn-steps__item__number" :style="{ backgroundColor: currentIndex <= index ? 'transparent' : activeColor, borderColor: currentIndex <= index ? inActiveColor : activeColor }" > <text class="tn-steps__item__number__text" :class="[{'tn-steps__item__number__text--visible': currentIndex <= index}]" :style="{ color: currentIndex <= index ? inActiveColor : activeColor }" > {{ index + 1}} </text> <view class="tn-steps__item__number__icon" :class="[`tn-icon-${item.icon || icon}`,{'tn-steps__item__number__icon--visible': currentIndex > index}]"></view> </view> <!-- 点模式 --> <view v-if="mode === 'dot'" class="tn-steps__item__dot" :style="{ backgroundColor: currentIndex <= index ? inActiveColor : activeColor, fontSize:fontSize }" ></view> <!-- 图标模式 --> <view v-if="mode === 'icon'" class="tn-steps__item__icon" :class="[iconModeClass(index)]" :style="{ color: currentIndex <= index ? inActiveColor : activeColor, fontSize:fontSize }" ></view> <!-- 点图标模式 --> <view v-if="mode === 'dotIcon'" class="tn-steps__item__dot-icon"> <view v-if="currentIndex <= index" class="tn-steps__item__dot-icon--dot" :style="{backgroundColor: inActiveColor}"></view> <view v-else class="tn-steps__item__dot-icon--icon" :class="[iconModeClass(index)]" :style="{color: activeColor}"></view> </view> <!-- 步骤下的文字 --> <text v-if="showTitle" class="tn-steps__item__text tn-text-ellipsis" :class="[`tn-steps__item__text--${direction}`]" :style="{ color: currentIndex <= index ? inActiveColor : activeColor, fontSize:fontSize }" > {{ item.name }} </text> <!-- 连接的横线 --> <view v-if="index < list.length - 1" class="tn-steps__item__line" :class="[`tn-steps__item__line--${mode}`]" :style="{ borderColor: currentIndex <= index + 1 ? inActiveColor : activeColor }" ></view> </view> </view> </template> <script> export default { name: 'tn-steps', props: { // 模式类型 // dot -> 点 number -> 数字 icon -> 图标 dotIcon -> 点图标 mode: { type: String, default: 'dot' }, // 步骤条的方向 // row -> 横向 column -> 竖向 direction: { type: String, default: 'row' }, // 步骤条数据 list: { type: Array, default() { return [] } }, // 当前激活的步数 current: { type: Number, default: 0 }, // 激活步骤的颜色 activeColor: { type: String, default: '#01BEFF' }, // 未激活步骤的颜色 inActiveColor: { type: String, default: '#AAAAAA' }, // 激活后显示的图标,在数字模式下有效 icon: { type: String, default: 'success' }, // 是否显示标题 showTitle: { type: Boolean, default: true }, fontSize:{ type: String, default: '14px' } }, computed: { // icon模式下图标的值 iconModeClass() { return (index) => { const item = this.list[index] // 状态被选中并且对应数据下存在selectIcon属性 if (this.currentIndex > index && item.hasOwnProperty('selectIcon')) { return `tn-icon-${item.selectIcon}` } else { // 未选中 return `tn-icon-${item.icon || this.icon}` } } } }, data() { return { currentIndex: 0 } }, watch: { current: { handler(val) { this.currentIndex = val }, immediate: true } }, methods: { // 点击了某一个选项 clickStepItem(index) { const chooseIndex = index + 1 this.currentIndex = chooseIndex this.$emit('click', { index: chooseIndex }) } } } </script> <style lang="scss" scoped> $tn-steps-item-number-width: 44rpx; $tn-steps-item-dot-width: 20rpx; .tn-steps { display: flex; flex-direction: row; &__item { flex: 1; position: relative; display: flex; align-items: center; justify-content: center; flex-direction: column; min-width: 100rpx; font-size: 28rpx; text-align: center; &__number { // display: flex; // flex-wrap: wrap; // align-items: center; // justify-content: center; position: relative; width: $tn-steps-item-number-width; height: $tn-steps-item-number-width; line-height: calc(#{$tn-steps-item-number-width} - 2rpx); border: 1px solid #AAAAAA; border-radius: 50%; overflow: hidden; transition: all 0.3s linear; &__text { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; transition: inherit; transform: translateY(-#{$tn-steps-item-number-width}); &--visible { transform: translateY(0); } } &__icon { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; color: #FFFFFF; transition: all 0.3s linear; transform: translateY(#{$tn-steps-item-number-width}); &--visible { transform: translateY(0); } } } &__dot { width: $tn-steps-item-dot-width; height: $tn-steps-item-dot-width; display: flex; flex-direction: row; border-radius: 50%; transition: all 0.3s linear; &--icon { width: $tn-steps-item-number-width; height: $tn-steps-item-number-width; } } &__icon { width: $tn-steps-item-number-width; height: $tn-steps-item-number-width; font-size: $tn-steps-item-number-width; transition: all 0.3s linear; } &__dot-icon { width: $tn-steps-item-number-width; height: $tn-steps-item-number-width; display: flex; flex-direction: row; align-items: center; justify-content: center; transition: all 0.3s linear; &--dot { width: $tn-steps-item-dot-width; height: $tn-steps-item-dot-width; border-radius: 50%; transition: inherit; } &--icon { width: $tn-steps-item-number-width; height: $tn-steps-item-number-width; font-size: $tn-steps-item-number-width; transition: inherit; } } &__text { transition: all 0.3s linear; &--row { margin-top: 14rpx; } &--column { margin-left: 14rpx; } } &__line { position: absolute; z-index: 0; vertical-align: middle; transition: all 0.3s linear; } &--row { display: flex; flex-direction: column; .tn-steps__item__line { border-bottom-width: 1px; border-bottom-style: solid; width: 50%; left: 75%; &--dot { top: calc(#{$tn-steps-item-dot-width} / 2); } &--number, &--icon, &--dotIcon { top: calc(#{$tn-steps-item-number-width} / 2); } } } &--column { display: flex; flex-direction: row; justify-content: flex-start; min-height: 120rpx; .tn-steps__item__line { border-left-width: 1px; border-left-style: solid; height: 50%; top: 75%; &--dot { left: calc(#{$tn-steps-item-dot-width} / 2); } &--number, &--icon, &--dotIcon { left: calc(#{$tn-steps-item-number-width} / 2); } } } } } </style>