You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
7.6 KiB
Vue

1 year ago
<template>
<view class="tm-steps" v-if="listLen>0">
<block v-for="(item,index) in list" :key="index">
<view class="tm-steps-item" :style="{
width:(100/listLen)+'%'
}">
<view class="tm-steps-item-text flex-center flex-col ">
<view :style="{
width:sizePx + 'px',
height:sizePx + 'px',
lineHeight:0
}" :class="[
index < value ? color_tmeme:'grey-lighten-4',
black_tmeme?'bk':'',
index < value?`shadow-${color_tmeme}-3`:''
]" @click.stop="itemclick(index)" class="tm-steps-item-text-icon rounded text-size-s flex-center ">
<block v-if="model=='number'">
<slot name="number"
:data="{icon:icon,activeIcon:activeIcon,index:index+1,active:index < value?true:false}">
<text :class="index < value ? '':'text-'+fontColor">{{index+1}}</text>
</slot>
</block>
<block v-if="model=='icon'">
<slot name="icon"
:data="{icon:icon,activeIcon:activeIcon,index:index+1,active:index < value?true:false}">
<tm-icons style="line-height: 0;" :color="fontColor" size="22" v-if="index >= value" :name="icon"></tm-icons>
<tm-icons style="line-height: 0;" color="white" size="22" v-if="index < value" :name="activeIcon"></tm-icons>
</slot>
</block>
</view>
<view :class="[
index < value ? `text-${activeFontColor_theme}`:`text-${fontColor}`,
]" class="tm-steps-item-text-icon-label text-size-s text-align-center px-10 py-16">
<slot name="default" :data="item">
{{item[rangeKey]?item[rangeKey]:item}}
</slot>
</view>
</view>
<view :style="{
width:` calc(100% - ${sizePx}px)`,
height:sizePx+'px',
top:`0`,
left: `calc(50% + ${sizePx/2}px)`,
}" v-if="index!==listLen-1" class="tm-steps-item-driver flex-center">
<!-- <tm-icons color="white" size="22" name="icon-angle-right"></tm-icons> -->
<view class="fulled flex-center"
:style="{borderTopStyle:lineStyle,borderTopWidth:lineWidth+'rpx',height:'1px'}"
:class="[index < value ? `border-${lineColor_theme}-t-1`:black_tmeme?'border-grey-darken-4-t-1':'border-grey-lighten-4-t-1']">
<view style="line-height: 0;">
<tm-icons v-if="lineInIcon" style="line-height: 0;" dense :color="index < value ? color_tmeme:'grey-lighten-4'" :black="black_tmeme" size="22" :name="lineInIcon"></tm-icons>
</view>
</view>
</view>
</view>
</block>
</view>
</template>
<script>
/**
* 步骤条
* @description 只能搭配tm-stepsItem组件使用内部需要放入tm-stepsItem组件
* @property {Number} value = [] 默认1当前第几步同步需要valu.snyc 推荐使用v-model.
* @property {Boolean} black = [true|false] 默认false暗黑模式
* @property {String} model = [number|icon] 默认number两种模式number:数字icon:图标模式
* @property {String} color = [] 默认primary主题色
* @property {String} range-key = [] 默认text数据为对象数组时需要提供对应的文字key
* @property {String} size = [] 默认42节点大小
* @property {String} line-color = [] 默认primary激活时的线条主题色
* @property {String} font-color = [] 默认grey文字主题色
* @property {String} active-font-color = [] 默认primary激活后的文字主题色
* @property {String} active-icon = [] 默认icon-check激活后的图标
* @property {String} icon = [] 默认icon-clock-fill未激活的图标
* @property {String} lineInIcon = [] 默认''节点间线中间内部的图标填写后显示不填写不显示
* @property {String} lineStyle = [] 默认solid标准的css边线类型
* @property {String} lineWidth = [] 默认1连接线的厚度单位rpx
* @property {Function} input 等同v-model参数
* @property {Function} change 步骤变化时触发等同input,v-model参数
* @property {Function} click 点击步骤节点时触发返回当前步骤位置
* @example <tm-steps v-model="star"><block v-for="(item,index) in 4" :key="index"><tm-stepsItem :fail="index+1==3" model="icon" :step="index+1"></tm-stepsItem><tm-divider :color="index > star-1 ? '#eeeeee':'#1976d2'" v-if="index!==3" ></tm-divider></block></tm-steps>
*/
import tmIcons from "@/tm-vuetify/components/tm-icons/tm-icons.vue"
export default {
components: {
tmIcons
},
name: "tm-steps",
model: {
prop: "value",
event: "input"
},
props: {
value: {
type: Number,
default: 1
},
list: {
type: Array,
default: () => {
return []
}
},
rangeKey: {
type: String,
default: 'text'
},
// 主题色。
color: {
type: String,
default: 'primary'
},
// 激活时的颜色值16进制。
lineColor: {
type: String,
default: 'primary'
},
lineStyle:{
type:String,
default:'solid',//solid,dashed
},
lineWidth:{
type:String|Number,
default:1,
},
//显示线上面的图标
lineInIcon:{
type:String,
default:'',
},
fontColor: {
type: String,
default: 'grey'
},
activeFontColor: {
type: String,
default: 'primary'
},
model: {
type: String,
default: 'icon'
},
black: {
type: Boolean | String,
default: null
},
size: {
type: Number,
default: 46
},
icon: {
type: String,
default: 'icon-clock-fill'
},
activeIcon: {
type: String,
default: 'icon-check'
},
// 跟随主题色的改变而改变。
fllowTheme: {
type: Boolean | String,
default: true
},
},
data() {
return {
};
},
computed: {
black_tmeme: function() {
if (this.black !== null) return this.black;
return this.$tm.vx.state().tmVuetify.black;
},
color_tmeme: function() {
if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this
.fllowTheme) {
return this.$tm.vx.state().tmVuetify.color;
}
return this.color;
},
lineColor_theme: function() {
if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this
.fllowTheme) {
return this.$tm.vx.state().tmVuetify.color;
}
return this.lineColor;
},
activeFontColor_theme: function() {
if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this
.fllowTheme) {
return this.$tm.vx.state().tmVuetify.color;
}
return this.activeFontColor;
},
listLen: function() {
if (!Array.isArray(this.list)) return 0;
return this.list.length;
},
sizePx: function() {
return uni.upx2px(this.size);
}
},
watch: {
value: async function() {
let bz = this.value;
if (this.value > this.listLen || this.value < 0) {
bz = 0
}
if (this.value == this.listLen - 1) {
bz = this.listLen - 1
}
await this.setActive(bz);
}
},
async mounted() {
this.UpdateItem();
},
methods: {
//如果需要动态插入步骤,需要调用此函数更新。
async UpdateItem() {
await this.setActive(this.value)
},
async setActive(index) {
this.$emit("input", index)
this.$emit("change", index)
this.$emit("update:value", index)
},
itemclick(index) {
this.$emit('click', index + 1)
}
},
}
</script>
<style lang="scss" scoped>
.tm-steps {
display: flex;
justify-content: space-between;
align-items: flex-start;
// border-style: dashed;
.tm-steps-item {
position: relative;
.tm-steps-item-text {
.tm-steps-item-text-icon {}
}
.tm-steps-item-driver {
position: absolute;
}
}
}
</style>