最近做的项目技术栈用的是jquery+requirejs+handlebar+公司内部的一套ui库。ui库中关于步骤条的只有简单的样式,如果设置下一步的时候需要一个节点一个节点的去设置样式,所以封装了一个步骤条的构造,现分享一下。
封装的步骤条可以实现的效果如下:
一、横向-从左开始
二、横向-从右开始
三、纵向-从上开始
四、纵向-从下开始
五、以上四种是封装的步骤条实现的效果。业务中用到的是第一种和第四种。
六、构造js代码
define([], function() {
'use strict';
/**
* 创建步骤条
* @param id - 容器id
* @param mode - left, right, top, bottom
* @param source - 步骤条数据 [{ label:"", value:"" }]
* @param defaultKey - 默认显示的步骤的key
* @param key - 步骤条唯一的key,默认为value
* @param showKey - 步骤条显示的key,默认为label
*
* @function setStepKey - 设置当前步骤条的位置(根据key值)
* @function setStepIndex - 设置当前步骤条的位置(根据index值)
* @function getCurrent - 获取当前步骤的信息 { key, index, item }
* @function setStepColor - 设置某一步的颜色值,该方法建议只是静态显示的时候使用
*/
function MyStep(option){
if(!option){
throw new Error('options is missing');
}
if(!option.id){
throw new Error('box id is missing');
}
this.id = option.id;
this.source = option.source || [];
if(this.source.length <= 1){
throw new Error('source length should > 1');
}
this.mode = option.mode || 'left';
this.key = option.key || 'value';
this.showKey = option.showKey || 'label';
this.box = document.getElementById(this.id);
this.init();
if(!option.defaultKey){
this.setStepIndex(0);
}else{
this.setStepKey(option.defaultKey);
}
}
MyStep.prototype.init = function(){
this.render();
}
MyStep.prototype.render = function(){
var that = this;
var str = '';
if(that.mode == "left" || that.mode == "right"){
str = '<div class="yby-steps-box left">';
var source = that.mode == "left" ? this.source : this.source.reverse();
source.forEach(function(item, index){
str += '<div class="step ' + (index == 0 ? "first" : index == that.source.length - 1 ? "last" : "") + '" style="flex-basis: ' + (100 / that.source.length) + '%;" data-key="' + item[that.key] + '">'
+ '<div class="circle-box">'
+ '<div class="circle-icon-box"><span class="circle"></span></div>'
+ '<div class="step-line"></div>'
+ '</div>'
+ '<div class="tips-box">'
+ '<span class="title">' + item[that.showKey] + '</span>'
+ '</div>'
+ '</div>';
})
str += '</div>';
}
else if(that.mode == "bottom" || that.mode == "top"){
str = '<div class="yby-steps-box bottom">';
var source = that.mode == "top" ? this.source : this.source.reverse();
source.forEach(function(item, index){
str += '<div class="step ' + (index == 0 ? "first" : index == that.source.length - 1 ? "last" : "") + '" data-key="' + item[that.key] + '">'
+ '<div class="circle-box">'
+ '<div class="circle-icon-box"><span class="circle"></span></div>'
+ '<div class="step-line"></div>'
+ '</div>'
+ '<div class="tips-box">'
+ '<div class="title-box">'
+ '<span class="title">' + item[that.showKey] + '</span>'
+ '<span class="date">'+ (item.date || '') +'</span>'
+ '</div>'
+ '<div class="msg">'+ (item.msg || '') +'</div>'
+ '</div>'
+ '<span class="clear"></span>'
+ '</div>';
})
str += '</div>';
}
this.box.innerHTML = str;
}
MyStep.prototype.setStepKey = function(key){
var that = this;
var flag = this.mode != "bottom" && this.mode != "right" ? false : true;
$(this.box).find('.step').map(function(index, item){
var aKey = $(item).data('key');
$(item).removeClass('active');
if(that.mode != "bottom" && that.mode != "right"){
if(!flag){
$(item).addClass('active');
}
flag = aKey == key ? !flag : flag;
}else{
flag = aKey == key ? !flag : flag;
if(!flag){
$(item).addClass('active');
}
}
})
}
MyStep.prototype.setStepIndex = function(index){
var len = this.source.length;
if(index >= len || index < 0){
throw new Error('index is out of range');
}
if(this.mode == "left" || this.mode == "top"){
$(this.box).find('.step').removeClass('active').eq(index).addClass('active').prevAll().addClass('active');
}
else if(this.mode == "bottom" || this.mode == "right"){
$(this.box).find('.step').removeClass('active').eq(len - 1 - index).addClass('active').nextAll().addClass('active');
}
}
MyStep.prototype.getCurrent = function(key){
var index = $(this.box).find('.step.active').length - 1;
var key = $(this.box).find('.step.active').eq(index).data('key');
var source = this.mode != "left" && this.mode != "top" ? this.source.reverse() : this.source;
var item = source[index];
return {
index: index,
key: key,
item: item
}
}
/**
* 来改变某一个节点的色值,这个方法只建议静态显示的时候用
* @param key - 唯一值
* @param color - 颜色值 rgb(247, 53, 53, 0.5) - 粉色;#f73535=rgb(247, 53, 53) - 红色
*/
MyStep.prototype.setStepColor = function(key, color){
$(this.box).find('.step').map(function(index, item){
var aKey = $(item).data('key');
if(aKey == key){
$(item).find('.circle').css({
border: '2px solid #e9ecf0',
backgroundColor: color
});
$(item).find('.text').css('color', color);
}
})
}
return MyStep;
});
七、组件的css代码
/*
步骤条样式
*/
.yby-steps-box.left {
width: 100%;
display: flex;
box-sizing: border-box;
margin: 20px auto;
}
.yby-steps-box.left * {
box-sizing: border-box;
}
.yby-steps-box.left .step {
align-items: center;
justify-content: space-between;
text-align: center;
}
.yby-steps-box.left .step .circle-box {
position: relative;
width: 100%;
height: 40px;
padding-top: 12px;
}
.yby-steps-box.left .step .circle-box .circle-icon-box {
position: absolute;
z-index: 5;
width: 100%;
}
.yby-steps-box.left .step .circle-box .circle-icon-box .circle {
width: 16px;
height: 16px;
border-radius: 50%;
display: inline-block;
background-color: #e9ecf0;
text-align: center;
}
.yby-steps-box.left .step .circle-box .step-line {
position: absolute;
width: 100%;
top: 20px;
font-size: 0;
border: none;
height: 2px;
background-color: #e9ecf0;
}
.yby-steps-box.left .step .tips-box .title {
display: inline-block;
width: 100px;
}
.yby-steps-box.left .step.active .circle-box .circle {
background-color: #90c31f;
border: 2px solid #e9ecf0;
}
.yby-steps-box.left .step.first .step-line {
width: 50%;
left: 50%;
}
.yby-steps-box.left .step.last .step-line {
width: 50%;
left: 0;
}
.yby-steps-box.bottom {
display: block;
width: 100%;
}
.yby-steps-box.bottom .step {
width: 100%;
height: 100px;
}
.yby-steps-box.bottom .step .circle-box {
float: left;
width: 100px;
height: 100%;
text-align: center;
position: relative;
}
.yby-steps-box.bottom .step .circle-box .circle-icon-box {
width: 100%;
height: 16px;
}
.yby-steps-box.bottom .step .circle-box .circle-icon-box .circle {
width: 16px;
height: 16px;
border-radius: 50%;
display: inline-block;
background-color: #e9ecf0;
text-align: center;
}
.yby-steps-box.bottom .step .circle-box .step-line {
position: absolute;
bottom: 0;
display: inline-block;
width: 2px;
font-size: 0;
border: none;
height: calc(100% - 16px);
background-color: #e9ecf0;
}
.yby-steps-box.bottom .step .tips-box {
float: right;
width: calc(100% - 100px);
}
.yby-steps-box.bottom .step .tips-box .title-box {
width: 100%;
height: 30px;
font-size: 13px;
}
.yby-steps-box.bottom .step .tips-box .title-box .title {
display: inline-block;
width: calc(100% - 150px);
color: #333333;
}
.yby-steps-box.bottom .step .tips-box .title-box .date {
float: right;
width: 150px;
text-align: right;
color: #999999;
}
.yby-steps-box.bottom .step .tips-box .msg {
width: calc(100% - 150px);
font-size: 12px;
line-height: 28px;
color: #999999;
}
.yby-steps-box.bottom .step .clear {
clear: both;
}
.yby-steps-box.bottom .step.active .circle-box .circle {
background-color: #90c31f;
border: 2px solid #e9ecf0;
}
.yby-steps-box.bottom .step.last .step-line {
display: none;
}
通过组件实例化之后的实例,可以调用实例的方法获取当前节点的信息,可以通过key或者index来设置步骤条的当前步骤。
就这么多了,构造中都有相应的注释,应该很明白了。