Steps步驟條組件源碼: ###<font color="blue">steps.vue</font>vue
<template> <!--設置 simple 可應用簡潔風格,該條件下 align-center / description / direction / space 都將失效。--> <div class="el-steps" :class="[ !simple && 'el-steps--' + direction, simple && 'el-steps--simple' ]"> <slot></slot> </div> </template> <script> import Migrating from 'element-ui/src/mixins/migrating'; export default { name: 'ElSteps', mixins: [Migrating], props: { space: [Number, String], //每一個 step 的間距,不填寫將自適應間距。支持百分比。 active: Number, //設置當前激活步驟 direction: { //顯示方向 type: String, default: 'horizontal' }, alignCenter: Boolean, //進行居中對齊 simple: Boolean, // 是否應用簡潔風格 finishStatus: { //設置結束步驟的狀態 type: String, default: 'finish' }, processStatus: { //設置當前步驟的狀態 type: String, default: 'process' } }, data() { return { steps: [], //記錄步驟數數組 stepOffset: 0 }; }, methods: { // 屬性遷移 getMigratingConfig() { return { props: { 'center': 'center is removed.' } }; } }, watch: { active(newVal, oldVal) { // 當前激活步驟改變時,觸發父組件的change方法,將改變前和改變後的步驟做爲參數傳遞出去 this.$emit('change', newVal, oldVal); }, steps(steps) { steps.forEach((child, index) => { child.index = index; }); } } }; </script>
###<font color="blue">step.vue</font>element-ui
<template> <!--每一步驟的最外層包裹div--> <div class="el-step" :style="style" :class="[ !isSimple && `is-${$parent.direction}`, isSimple && 'is-simple', isLast && !space && !isCenter && 'is-flex', isCenter && !isVertical && !isSimple && 'is-center' ]"> <!-- 步驟的數字圖標和步驟條直線 --> <div class="el-step__head" :class="`is-${currentStatus}`"> <!--步驟條直線--> <!--若是是最後一步,margin-right不存在;若是不是,則爲0--> <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'}`"> <!--若是當前狀態爲:wait、process、finish--> <slot v-if="currentStatus !== 'success' && currentStatus !== 'error'" name="icon"> <!--若是是圖標則顯示對應的圖標--> <i v-if="icon" class="el-step__icon-inner" :class="[icon]"></i> <!--若是圖標和未設置isSimple簡潔風格時,則顯示步驟文字--> <div class="el-step__icon-inner" v-if="!icon && !isSimple">{{ index + 1 }}</div> </slot> <!--若是當前狀態爲:success、error--> <i v-else :class="['el-icon-' + (currentStatus === 'success' ? 'check' : 'close')]" class="el-step__icon-inner is-status"></i> </div> </div> <!-- 步驟條下面每一步的標題和描述 --> <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 //設置當前步驟的狀態,不設置則根據 steps 肯定狀態。 wait(灰色)/ process(黑色)/ finish(藍色)/ error / success(綠色) }, data() { return { index: -1, lineStyle: {}, //步驟條直線的樣式 internalStatus: '' }; }, beforeCreate() { this.$parent.steps.push(this); }, mounted() { const unwatch = this.$watch('index', val => { this.$watch('$parent.active', this.updateStatus, { immediate: true }); unwatch(); }); }, 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; }, // 返回顯示的方向:豎直(false)或者水平(true) 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; }, // 返回每一個step的間距。 space() { const { isSimple, $parent: { space } } = this; // isSimple爲true時,space將失效 return isSimple ? '' : space ; }, style: function() { const style = {}; const parent = this.$parent; const len = parent.steps.length; //總步驟 // 每一個step的間距 const space = (typeof this.space === 'number' //若是設置的space是number ? this.space + 'px' //space等於設置的space : this.space ? this.space : 100 / (len - (this.isCenter ? 0 : 1)) + '%'); //若是未設置space,未設置居中,則等於100除以(總步驟數-1);設置居中顯示,則等於00除以總步驟數。 // flex-basis 屬性用於設置或檢索彈性盒伸縮基準值。 style.flexBasis = space; //若是是水平方向則直接返回設置的樣式 if (this.isVertical) return style; //若是是最後的步驟,設置最大寬度等於(100/總步驟數)% if (this.isLast) { style.maxWidth = 100 / this.stepsCount + '%'; } else { //若是不是最後的步驟,marginRight爲0 style.marginRight = -this.$parent.stepOffset + 'px'; } return style; } }, methods: { updateStatus(val) { const prevChild = this.$parent.$children[this.index - 1]; if (val > this.index) { //若是是下一步 // internalStatus 等於用戶設置的結束步驟狀態 this.internalStatus = this.$parent.finishStatus; } else if (val === this.index && this.prevStatus !== 'error') { // internalStatus 等於用戶設置的當前步驟狀態 this.internalStatus = this.$parent.processStatus; } else { this.internalStatus = 'wait'; } if (prevChild) prevChild.calcProgress(this.internalStatus); }, //設置步驟間直線的樣式 calcProgress(status) { let step = 100; const style = {}; // transitionDelay在過渡效果開始前等待的秒數: 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 ? '1px' : 0; this.$parent.direction === 'vertical' ? style.height = step + '%' : style.width = step + '%'; this.lineStyle = style; } } }; </script>