<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>