347 lines
8.6 KiB
Vue
347 lines
8.6 KiB
Vue
<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
|
|
}"
|
|
></view>
|
|
|
|
<!-- 图标模式 -->
|
|
<view
|
|
v-if="mode === 'icon'"
|
|
class="tn-steps__item__icon"
|
|
:class="[iconModeClass(index)]"
|
|
:style="{
|
|
color: currentIndex <= index ? inActiveColor : activeColor
|
|
}"
|
|
></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
|
|
}"
|
|
>
|
|
{{ 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
|
|
}
|
|
},
|
|
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>
|