element/packages/steps/src/step.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>