3.29 Steps 步骤条
简介
步骤条组件Steps是引导用户按照流程完成任务的分步导航条。当任务复杂或者存在先后关系时,将其分解成一系列步骤,从而简化任务,一半步骤不得少于 2 步。
本文将分析其源码实现,耐心读完,相信会对您有所帮助。🔗 组件文档 Steps 🔗 gitee源码
更多组件剖析详见 👉 📚 Element 2 源码剖析组件总览 。
组件源码
步骤条功能提供了两个组件:顶层组件el-steps和 子组件el-step。
各组件的 prop 声明,各属性功能说明详见官方文档 Steps#attributes 。
顶层组件 steps.vue
顶层组件基本上就是一个容器,包含着子组件el-step用到的共享状态。在el-step中直接通过$parent获取父实例,改变和同步其共享状态。
模板渲染成一个类名el-steps的简单div元素,同时使用匿名插槽渲染步骤元素。
声明
props用于外部传入的属性。属性
steps用于保存当前实例下子组件el-step的实例数组。属性
stepOffset用于设置步骤元素的间隔。定义了侦听器,监听属性
active用于触发的自定义change事件,监听属性steps更新每个子组件实例步骤索引。
// packages\steps\src\steps.vue
<template>
<div
class="el-steps"
:class="[
!simple && 'el-steps--' + direction,
simple && 'el-steps--simple'
]">
<slot></slot>
</div>
</template>
<script>
export default {
// props ...
data() {
return {
steps: [],
stepOffset: 0
};
},
watch: {
active(newVal, oldVal) {
this.$emit('change', newVal, oldVal);
},
steps(steps) {
steps.forEach((child, index) => {
child.index = index;
});
}
}
};
</script> 步骤组件状态初始化
为了更好理解步骤组件一些状态初始化操作, 接下结合父子组件的生命周期流程进行讲解。
父子组件实例在创建时经历一系列的初始化步骤:
父beforeCreate -> 父created -> 父beforeMount ->子beforeCreate -> 子created -> 子beforeMount -> 子mounted-> 父mounted。
首先,顶层组件el-steps初始化实例、 解析props、data()和侦听器等选项设置完毕。
其次,子组件el-step初始化实例、 解析props、data() 、计算属性、方法和侦听器等选项设置完毕。定义了beforeCreate钩子函数,当子组件实例初始化完成之后立即将该实例添加至父组件的属性steps数组中。
再次,定义了mounted钩子函数,当子组件el-step被挂载之后,使用命令式的 $watch() 创建侦听器。用于监听属性index更改,执行侦听回调一次后,调用方法unwatch()就会停止该侦听器。
然后,顶层组件的属性steps数组长度大于0,会执行侦听回调,更新每个子组件实例的属性 index值,即实例在数组steps中索引值。
然后,触发子组件的index的属性侦听回调,此时会在子组件创建侦全局状态active、processStatus的侦听器,用于更新各个子组件的状态显示。用于触发回调方法updateStatus,参数是当前激活步骤的index。
最后,执行方法 updateStatus,初始化子组件状态。因为定义了immediate: true,在侦听器创建时立即方法,所以会调用两次方法。
子组件有三个内部状态(隐式) 激活/已完成/未激活,使用属性internalStatus表示内部状态值(显式)。
已完成当前激活步骤索引大于此步骤所在数组索引值,internalStatus值为属性finishStatus值。激活当前激活步骤索引等于步骤所在数组索引值,若非首元素,则上一步骤元素的状态值不能为error,也就是error会中断步骤流程。internalStatus值为属性processStatus值。未激活当前激活步骤索引小于此步骤所在数组索引值,internalStatus值为wait。
根据当前子组件的索引,获取它的上一元素prevChild,调用prevChild的方法prevChildcalcProgress计算步骤间轴线样式,此方法稍后会详细介绍。
步骤的状态
上面介绍了整个初始化的流程,也许大家会有疑惑,动态更新的属性internalStatus值作用是什么?
步骤组件提供了属性status值用于设置当前步骤的状态值;如果未设置, 就会根据属性internalStatus确定状态值。
计算属性currentStatus返回当前步骤的状态值,计算属性 prevStatus 返回上一步骤的状态值。
步骤组件 step.vue
步骤条主要功能实现都在该组件中。
HTML
模板渲染成一个类名el-step的div元素,元素包含两部分内容
用于图标、轴线的渲染。
用于标题、描述的渲染。
下图是不同状态步骤的展示效果:
步骤元素通过内联样式和动态类名渲染不同配置下组件样式。
根元素自定义类名
文档中提到当设置
simple可应用简洁风格,该条件下align-center、direction、space都将失效。
接下将一一分析为什么设置会失效。
属性 direction 用于设置显示方向,生成类名 is-vertical或 is-horizontal。根据计算属性isSimple判断设置简洁风格时,只会生成类名 is-simple。
顶层组件中也会根据属性simple、direction生成根元素类名el-steps--simple 、el-steps--vertical或el-steps--horizontal。
如果未设置间距 space和居中对齐 alignCenter,步骤条末元素会生成类名 is-flex用于自适应宽度。 如果设置了简洁风格,计算属性space中属性space设置无效。
非简洁模式和竖直方向下,设置居中对齐 alignCenter才会生效,生成类名is-center。
根元素内联样式
顶层组件 steps 的根元素采用 flex布局。
计算属性style根据属性 space 设置flex-basis,指定了 flex 元素在主轴方向上的初始大小,也就是内容盒(content-box)的尺寸。相当于设置了步骤元素的 width 或 height。
当一个元素同时被设置了
flex-basis(除值为auto外) 和width(或者在flex-direction: column情况下设置了height) ,flex-basis具有更高的优先级。
传入的属性 space值类型为 number时生成格式 {20}px。不设置根据步骤个数自动计算百分比实现自适应间距。
水平方向时,步骤末元素设置属性max-width值,其余设置属性margin-right值(属性stepOffset值没有相关计算或赋值,始终为 0)。
属性 space 可设置值可以参考以下内容:
下面通过运行实例对比分析下,各属性设置的渲染效果。
步骤元素内容个数相同情况下,不同设置的效果如下:
各步骤元素DOM结构如下(此处不考虑内部内容样式区别),除了第一个示例,其余每个步骤都是等分。
那问题来了,第一个示例中 space 未设置,组件会自适应宽度操作,那么末步骤元素发生了什么导致其宽度跟其他步骤元素不一致?
第一个示例DOM结构渲染如下,虽然都设置了flex-basis: 33.3333%;,但是末元素的未生效。
因为末元素添加了样式类名is-flex,覆盖了flex-basis,等同于 flex: none 或 flex: 0 0 auto。元素会根据自身宽高来设置尺寸。它是完全非弹性的:既不会缩短,也不会伸长来适应 flex 容器。
上文中提到非简洁模式下,只有未设置间距 space和居中对齐 alignCenter时,步骤条末元素会生成类名 is-flex。这也是第二、三示例末元素跟其他元素宽度一致原因。
竖直方向样式逻辑与水平一致(alignCenter设置无效),此处不再赘述。
图标 & 轴线
根据计算属性currentStatus生成当前步骤状态对应的主题样式 is-[wait/process/finish/error/success]
图标
图标元素是类名el-step__icon的div元素,提供了具名icon插槽自定义步骤节点图标。插槽内容默认展示Icon图标或表示节点顺序圆环数字(从1开始)。简洁风格下,只有Icon设置生效。
当组件状态值为 success 或 error 时,使用系统提供图标。
数字圆环的样式is-text设置的。
不同设置组件效果对比如下:
设置居中对齐 alignCenter时,图标的居中效果是通过样式控制的。
轴线
轴线元素是类名el-step__line的div元素,使用了绝对布局。
通过偏移量、height、width等属性设置轴线位置、长度以及粗细。
使用了伪类:last-of-type 设置最后一个步骤元素中轴线不显示。
居中对齐下的轴线偏移量有些特殊,渲染效果如下。
实际元素DOM结构如下:
轴线进度状态效果通过类名el-step__line-inner元素实现,该元素内联样式绑定属性lineStyle。
属性lineStyle通过方法calcProgress根据当前步骤的状态计算而来。 方法updateStatus作用在生命周期中详细介绍过。
当前步骤元素不是第一个,此时步骤的状态为已完成,就会更新其上一元素的 lineStyle 值,显示进度效果。
标题 & 描述
标题是类名el-step__title的div元素,提供了具名title插槽用于自定义标题,后备插槽内容为属性 title值。
描述类名el-step__description的div元素,提供了具名description插槽用于自定义描述性文字,后备插槽内容为属性 description值。简洁风格下,description 设置失效。
它们根据计算属性currentStatus生成当前步骤状态对应的主题样式 is-[wait/process/finish/error/success]。
简洁风格
前面章节中介绍了简洁风格会导致很多设置无效,接下来整体的看下简洁风格的实现效果。
此时DOM结构渲染如下。
此时步骤元素使用flex布局,所以图标、标题、 箭头元素都在一行内展示。
轴线元素DOM渲染了,但是没有设置宽、高、边框粗细,页面就无法展示。
箭头样式使用伪类:before、:after定义。
样式实现
组件样式源码 packages\theme-chalk\src\steps.scss 使用混合指令嵌套生成组件样式。
组件样式源码 packages\theme-chalk\src\step.scss 使用混合指令嵌套生成组件样式。
📚参考&关联阅读
'CSS/flex',MDN 'CSS/:last-of-type',MDN '生命周期',vuejs 'watch',vuejs
最后更新于