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.

317 lines
7.6 KiB
Vue

4 months ago
<template>
<view class="u-steps-item" ref="u-steps-item" :class="[`u-steps-item--${parentData.direction}`]">
<view class="u-steps-item__line" v-if="index + 1 < childLength"
:class="[`u-steps-item__line--${parentData.direction}`]" :style="[lineStyle]"></view>
<view class="u-steps-item__wrapper"
:class="[`u-steps-item__wrapper--${parentData.direction}`, parentData.dot && `u-steps-item__wrapper--${parentData.direction}--dot`]">
<slot name="icon">
<view class="u-steps-item__wrapper__dot" v-if="parentData.dot" :style="{
backgroundColor: statusColor
}">
</view>
<view class="u-steps-item__wrapper__icon" v-else-if="parentData.activeIcon || parentData.inactiveIcon">
<u-icon :name="index <= parentData.current ? parentData.activeIcon : parentData.inactiveIcon"
:size="iconSize"
:color="index <= parentData.current ? parentData.activeColor : parentData.inactiveColor">
</u-icon>
</view>
<view v-else :style="{
backgroundColor: statusClass === 'process' ? parentData.activeColor : 'transparent',
borderColor: statusColor
}" class="u-steps-item__wrapper__circle">
<text v-if="statusClass === 'process' || statusClass === 'wait'"
class="u-steps-item__wrapper__circle__text" :style="{
color: index == parentData.current ? '#ffffff' : parentData.inactiveColor
}">{{ index + 1}}</text>
<u-icon v-else :color="statusClass === 'error' ? 'error' : parentData.activeColor" size="12"
:name="statusClass === 'error' ? 'close' : 'checkmark'"></u-icon>
</view>
</slot>
</view>
<view class="u-steps-item__content" :class="[`u-steps-item__content--${parentData.direction}`]"
:style="[contentStyle]">
<u--text :text="title" :type="parentData.current == index ? 'main' : 'content'" lineHeight="20px"
:size="parentData.current == index ? 14 : 13"></u--text>
<slot name="desc">
<u--text :text="desc" type="tips" size="12"></u--text>
</slot>
</view>
<!-- <view
class="u-steps-item__line"
v-if="showLine && parentData.direction === 'column'"
:class="[`u-steps-item__line--${parentData.direction}`]"
:style="[lineStyle]"
></view> -->
</view>
</template>
<script>
import props from './props.js';
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom')
// #endif
/**
* StepsItem 步骤条的子组件
* @description 本组件需要和u-steps配合使用
* @tutorial https://uviewui.com/components/steps.html
* @property {String} title 标题文字
* @property {String} current 描述文本
* @property {String | Number} iconSize 图标大小 (默认 17 )
* @property {Boolean} error 当前步骤是否处于失败状态 (默认 false )
* @example <u-steps current="0"><u-steps-item title="已出库" desc="10:35" ></u-steps-item></u-steps>
*/
export default {
name: 'u-steps-item',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
index: 0,
childLength: 0,
showLine: false,
size: {
height: 0,
width: 0
},
parentData: {
direction: 'row',
current: 0,
activeColor: '',
inactiveColor: '',
activeIcon: '',
inactiveIcon: '',
dot: false
}
}
},
watch: {
'parentData'(newValue, oldValue) {
}
},
created() {
this.init()
},
computed: {
lineStyle() {
const style = {}
if (this.parentData.direction === 'row') {
style.width = this.size.width + 'px'
style.left = this.size.width / 2 + 'px'
} else {
style.height = this.size.height + 'px'
// style.top = this.size.height / 2 + 'px'
}
style.backgroundColor = this.parent.children?.[this.index + 1]?.error ? uni.$u.color.error : this.index <
this
.parentData
.current ? this.parentData.activeColor : this.parentData.inactiveColor
return style
},
statusClass() {
const {
index,
error
} = this
const {
current
} = this.parentData
if (current == index) {
return error === true ? 'error' : 'process'
} else if (error) {
return 'error'
} else if (current > index) {
return 'finish'
} else {
return 'wait'
}
},
statusColor() {
let color = ''
switch (this.statusClass) {
case 'finish':
color = this.parentData.activeColor
break
case 'error':
color = uni.$u.color.error
break
case 'process':
color = this.parentData.dot ? this.parentData.activeColor : 'transparent'
break
default:
color = this.parentData.inactiveColor
break
}
return color
},
contentStyle() {
const style = {}
if (this.parentData.direction === 'column') {
style.marginLeft = this.parentData.dot ? '2px' : '6px'
style.marginTop = this.parentData.dot ? '0px' : '6px'
} else {
style.marginTop = this.parentData.dot ? '2px' : '6px'
style.marginLeft = this.parentData.dot ? '2px' : '6px'
}
return style
}
},
mounted() {
this.parent && this.parent.updateFromChild()
uni.$u.sleep().then(() => {
this.getStepsItemRect()
})
},
methods: {
init() {
// 初始化数据
this.updateParentData()
if (!this.parent) {
return uni.$u.error('u-steps-item必须要搭配u-steps组件使用')
}
this.index = this.parent.children.indexOf(this)
this.childLength = this.parent.children.length
},
updateParentData() {
// 此方法在mixin中
this.getParentData('u-steps')
},
// 父组件数据发生变化
updateFromParent() {
this.init()
},
// 获取组件的尺寸,用于设置横线的位置
getStepsItemRect() {
// #ifndef APP-NVUE
this.$uGetRect('.u-steps-item').then(size => {
this.size = size
})
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['u-steps-item'], res => {
const {
size
} = res
this.size = size
})
// #endif
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-steps-item {
flex: 1;
@include flex;
&--row {
flex-direction: column;
align-items: center;
position: relative;
}
&--column {
position: relative;
flex-direction: row;
justify-content: flex-start;
padding-bottom: 5px;
}
&__wrapper {
@include flex;
justify-content: center;
align-items: center;
position: relative;
background-color: #fff;
&--column {
width: 20px;
height: 32px;
&--dot {
height: 20px;
width: 20px;
}
}
&--row {
width: 32px;
height: 20px;
&--dot {
width: 20px;
height: 20px;
}
}
&__circle {
width: 20px;
height: 20px;
/* #ifndef APP-NVUE */
box-sizing: border-box;
flex-shrink: 0;
/* #endif */
border-radius: 100px;
border-width: 1px;
border-color: $u-tips-color;
border-style: solid;
@include flex(row);
align-items: center;
justify-content: center;
transition: background-color 0.3s;
&__text {
color: $u-tips-color;
font-size: 11px;
@include flex(row);
align-items: center;
justify-content: center;
text-align: center;
line-height: 11px;
}
}
&__dot {
width: 10px;
height: 10px;
border-radius: 100px;
background-color: $u-content-color;
}
}
&__content {
@include flex;
flex: 1;
&--row {
flex-direction: column;
align-items: center;
}
&--column {
flex-direction: column;
margin-left: 6px;
}
}
&__line {
position: absolute;
background: $u-tips-color;
&--row {
top: 10px;
height: 1px;
}
&--column {
width: 1px;
left: 10px;
}
}
}
</style>