step.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <template>
  2. <div
  3. class="el-step"
  4. :style="style"
  5. :class="[
  6. !isSimple && `is-${$parent.direction}`,
  7. isSimple && 'is-simple',
  8. isLast && !space && !isCenter && 'is-flex',
  9. isCenter && !isVertical && !isSimple && 'is-center'
  10. ]">
  11. <!-- icon & line -->
  12. <div
  13. class="el-step__head"
  14. :class="`is-${currentStatus}`">
  15. <div
  16. class="el-step__line"
  17. :style="isLast ? '' : { marginRight: $parent.stepOffset + 'px' }"
  18. >
  19. <i class="el-step__line-inner" :style="lineStyle"></i>
  20. </div>
  21. <div class="el-step__icon" :class="`is-${icon ? 'icon' : 'text'}`">
  22. <slot
  23. v-if="currentStatus !== 'success' && currentStatus !== 'error'"
  24. name="icon">
  25. <i v-if="icon" class="el-step__icon-inner" :class="[icon]"></i>
  26. <div class="el-step__icon-inner" v-if="!icon && !isSimple">{{ index + 1 }}</div>
  27. </slot>
  28. <i
  29. v-else
  30. :class="['el-icon-' + (currentStatus === 'success' ? 'check' : 'close')]"
  31. class="el-step__icon-inner is-status"
  32. >
  33. </i>
  34. </div>
  35. </div>
  36. <!-- title & description -->
  37. <div class="el-step__main">
  38. <div
  39. class="el-step__title"
  40. ref="title"
  41. :class="['is-' + currentStatus]">
  42. <slot name="title">{{ title }}</slot>
  43. </div>
  44. <div v-if="isSimple" class="el-step__arrow"></div>
  45. <div
  46. v-else
  47. class="el-step__description"
  48. :class="['is-' + currentStatus]">
  49. <slot name="description">{{ description }}</slot>
  50. </div>
  51. </div>
  52. </div>
  53. </template>
  54. <script>
  55. export default {
  56. name: 'ElStep',
  57. props: {
  58. title: String,
  59. icon: String,
  60. description: String,
  61. status: String
  62. },
  63. data() {
  64. return {
  65. index: -1,
  66. lineStyle: {},
  67. internalStatus: ''
  68. };
  69. },
  70. beforeCreate() {
  71. this.$parent.steps.push(this);
  72. },
  73. beforeDestroy() {
  74. const steps = this.$parent.steps;
  75. const index = steps.indexOf(this);
  76. if (index >= 0) {
  77. steps.splice(index, 1);
  78. }
  79. },
  80. computed: {
  81. currentStatus() {
  82. return this.status || this.internalStatus;
  83. },
  84. prevStatus() {
  85. const prevStep = this.$parent.steps[this.index - 1];
  86. return prevStep ? prevStep.currentStatus : 'wait';
  87. },
  88. isCenter() {
  89. return this.$parent.alignCenter;
  90. },
  91. isVertical() {
  92. return this.$parent.direction === 'vertical';
  93. },
  94. isSimple() {
  95. return this.$parent.simple;
  96. },
  97. isLast() {
  98. const parent = this.$parent;
  99. return parent.steps[parent.steps.length - 1] === this;
  100. },
  101. stepsCount() {
  102. return this.$parent.steps.length;
  103. },
  104. space() {
  105. const { isSimple, $parent: { space } } = this;
  106. return isSimple ? '' : space ;
  107. },
  108. style: function() {
  109. const style = {};
  110. const parent = this.$parent;
  111. const len = parent.steps.length;
  112. const space = (typeof this.space === 'number'
  113. ? this.space + 'px'
  114. : this.space
  115. ? this.space
  116. : 100 / (len - (this.isCenter ? 0 : 1)) + '%');
  117. style.flexBasis = space;
  118. if (this.isVertical) return style;
  119. if (this.isLast) {
  120. style.maxWidth = 100 / this.stepsCount + '%';
  121. } else {
  122. style.marginRight = -this.$parent.stepOffset + 'px';
  123. }
  124. return style;
  125. }
  126. },
  127. methods: {
  128. updateStatus(val) {
  129. const prevChild = this.$parent.$children[this.index - 1];
  130. if (val > this.index) {
  131. this.internalStatus = this.$parent.finishStatus;
  132. } else if (val === this.index && this.prevStatus !== 'error') {
  133. this.internalStatus = this.$parent.processStatus;
  134. } else {
  135. this.internalStatus = 'wait';
  136. }
  137. if (prevChild) prevChild.calcProgress(this.internalStatus);
  138. },
  139. calcProgress(status) {
  140. let step = 100;
  141. const style = {};
  142. style.transitionDelay = 150 * this.index + 'ms';
  143. if (status === this.$parent.processStatus) {
  144. step = this.currentStatus !== 'error' ? 0 : 0;
  145. } else if (status === 'wait') {
  146. step = 0;
  147. style.transitionDelay = (-150 * this.index) + 'ms';
  148. }
  149. style.borderWidth = step && !this.isSimple ? '1px' : 0;
  150. this.$parent.direction === 'vertical'
  151. ? style.height = step + '%'
  152. : style.width = step + '%';
  153. this.lineStyle = style;
  154. }
  155. },
  156. mounted() {
  157. const unwatch = this.$watch('index', val => {
  158. this.$watch('$parent.active', this.updateStatus, { immediate: true });
  159. this.$watch('$parent.processStatus', () => {
  160. const activeIndex = this.$parent.active;
  161. this.updateStatus(activeIndex);
  162. }, { immediate: true });
  163. unwatch();
  164. });
  165. }
  166. };
  167. </script>