mirror of https://github.com/ElemeFE/element
185 lines
4.7 KiB
Vue
185 lines
4.7 KiB
Vue
<template>
|
|
<div
|
|
class="el-step"
|
|
:style="style"
|
|
:class="[
|
|
!isSimple && `is-${$parent.direction}`,
|
|
isSimple && 'is-simple',
|
|
isLast && !space && !isCenter && 'is-flex',
|
|
isCenter && !isVertical && !isSimple && 'is-center'
|
|
]">
|
|
<!-- icon & line -->
|
|
<div
|
|
class="el-step__head"
|
|
:class="`is-${currentStatus}`">
|
|
<div
|
|
class="el-step__line"
|
|
:style="isLast ? '' : { marginRight: $parent.stepOffset + 'px' }"
|
|
>
|
|
<i class="el-step__line-inner" :style="lineStyle"></i>
|
|
</div>
|
|
|
|
<div class="el-step__icon" :class="`is-${icon ? 'icon' : 'text'}`">
|
|
<slot
|
|
v-if="currentStatus !== 'success' && currentStatus !== 'error'"
|
|
name="icon">
|
|
<i v-if="icon" class="el-step__icon-inner" :class="[icon]"></i>
|
|
<div class="el-step__icon-inner" v-if="!icon && !isSimple">{{ index + 1 }}</div>
|
|
</slot>
|
|
<i
|
|
v-else
|
|
:class="['el-icon-' + (currentStatus === 'success' ? 'check' : 'close')]"
|
|
class="el-step__icon-inner is-status"
|
|
>
|
|
</i>
|
|
</div>
|
|
</div>
|
|
<!-- title & description -->
|
|
<div class="el-step__main">
|
|
<div
|
|
class="el-step__title"
|
|
ref="title"
|
|
:class="['is-' + currentStatus]">
|
|
<slot name="title">{{ title }}</slot>
|
|
</div>
|
|
<div v-if="isSimple" class="el-step__arrow"></div>
|
|
<div
|
|
v-else
|
|
class="el-step__description"
|
|
:class="['is-' + currentStatus]">
|
|
<slot name="description">{{ description }}</slot>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'ElStep',
|
|
|
|
props: {
|
|
title: String,
|
|
icon: String,
|
|
description: String,
|
|
status: String
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
index: -1,
|
|
lineStyle: {},
|
|
internalStatus: ''
|
|
};
|
|
},
|
|
|
|
beforeCreate() {
|
|
this.$parent.steps.push(this);
|
|
},
|
|
|
|
beforeDestroy() {
|
|
const steps = this.$parent.steps;
|
|
const index = steps.indexOf(this);
|
|
if (index >= 0) {
|
|
steps.splice(index, 1);
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
currentStatus() {
|
|
return this.status || this.internalStatus;
|
|
},
|
|
prevStatus() {
|
|
const prevStep = this.$parent.steps[this.index - 1];
|
|
return prevStep ? prevStep.currentStatus : 'wait';
|
|
},
|
|
isCenter() {
|
|
return this.$parent.alignCenter;
|
|
},
|
|
isVertical() {
|
|
return this.$parent.direction === 'vertical';
|
|
},
|
|
isSimple() {
|
|
return this.$parent.simple;
|
|
},
|
|
isLast() {
|
|
const parent = this.$parent;
|
|
return parent.steps[parent.steps.length - 1] === this;
|
|
},
|
|
stepsCount() {
|
|
return this.$parent.steps.length;
|
|
},
|
|
space() {
|
|
const { isSimple, $parent: { space } } = this;
|
|
return isSimple ? '' : space ;
|
|
},
|
|
style: function() {
|
|
const style = {};
|
|
const parent = this.$parent;
|
|
const len = parent.steps.length;
|
|
|
|
const space = (typeof this.space === 'number'
|
|
? this.space + 'px'
|
|
: this.space
|
|
? this.space
|
|
: 100 / (len - (this.isCenter ? 0 : 1)) + '%');
|
|
style.flexBasis = space;
|
|
if (this.isVertical) return style;
|
|
if (this.isLast) {
|
|
style.maxWidth = 100 / this.stepsCount + '%';
|
|
} else {
|
|
style.marginRight = -this.$parent.stepOffset + 'px';
|
|
}
|
|
|
|
return style;
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
updateStatus(val) {
|
|
const prevChild = this.$parent.$children[this.index - 1];
|
|
|
|
if (val > this.index) {
|
|
this.internalStatus = this.$parent.finishStatus;
|
|
} else if (val === this.index && this.prevStatus !== 'error') {
|
|
this.internalStatus = this.$parent.processStatus;
|
|
} else {
|
|
this.internalStatus = 'wait';
|
|
}
|
|
|
|
if (prevChild) prevChild.calcProgress(this.internalStatus);
|
|
},
|
|
|
|
calcProgress(status) {
|
|
let step = 100;
|
|
const style = {};
|
|
|
|
style.transitionDelay = 150 * this.index + 'ms';
|
|
if (status === this.$parent.processStatus) {
|
|
step = this.currentStatus !== 'error' ? 0 : 0;
|
|
} else if (status === 'wait') {
|
|
step = 0;
|
|
style.transitionDelay = (-150 * this.index) + 'ms';
|
|
}
|
|
|
|
style.borderWidth = step && !this.isSimple ? '1px' : 0;
|
|
this.$parent.direction === 'vertical'
|
|
? style.height = step + '%'
|
|
: style.width = step + '%';
|
|
|
|
this.lineStyle = style;
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
const unwatch = this.$watch('index', val => {
|
|
this.$watch('$parent.active', this.updateStatus, { immediate: true });
|
|
this.$watch('$parent.processStatus', () => {
|
|
const activeIndex = this.$parent.active;
|
|
this.updateStatus(activeIndex);
|
|
}, { immediate: true });
|
|
unwatch();
|
|
});
|
|
}
|
|
};
|
|
</script>
|