需求背景:用户参加某个活动,需要展示活动整体流程及用户当前操作在流程中的位置,支持左右滑动查看、自动定位到最新状态。
项目使用原生小程序开发,不使用第三方UI库。
样式参考如下图:
实现思路&代码如下:
新建一个components,使用时引入到页面中,或者直接在Page中写也可以。
- wxml
由于需要支持左右滑动,以及自动定位到最新激活状态的节点,布局使用微信小程序的scroll-view组件可以很好实现,使用:
scroll-x 设置允许横向滑动
scroll-into-view 值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素
enable-flex 开启flex布局
show-scrollbar 设置滚动条是否显示
每个节点包括图标/图片、文案、连接线,图标和连接线都有激活和非激活两种状态,对应两种样式。
我这里是根据 item.isActived 的值判断节点是否为激活态设置对应的样式
<scroll-view class="step-list" scroll-into-view="{{goStatus}}" scroll-x="{{true}}" enable-flex="{{true}}" enhanced show-scrollbar="false">
<view wx:for="{{statusEnum}}" wx:key="status" id="{{item.status}}" class="step-con">
<view wx:if="{{index > 0}}" class="{{item.isActived ? 'actived-line' : 'deactived-line'}} "></view>
<view class="item">
<view class="iconfont step-iconfont icon-{{item.isActived ? item.activedIcon :item.deActivedIcon}}"></view>
<view class="step-tips {{item.isActived ? 'actived-tips' : 'deactived-tips'}}">{{item.value}}</view>
</view>
</view>
</scroll-view>
- js
定义一个数组statusEnum存放所有进度条节点数据,数组中每一项包括:status、value、isActived、deActivedIcon、activedIcon,具体含义可以看代码注释部分。
定义变量goStatus标识要滚动到那个节点,默认值为第一个节点
定义方法 handelSteps 处理进度条数据
// js代码
data: {
// 进度条数据初始化
statusEnum: [{
status: 'step1', // 进度条状态,一般需要与后端给的状态枚举值对齐
value: '进度1', // 状态文案
isActived: true, // 标记是否到达当前状态,即active激活态
// 图标我用的iconfont,也可以不同状态使用不同图标/图片
deActivedIcon: 'weixuanzhong', // 非active态iconfont图标,图片的话就写路径
activedIcon: 'gouxuan', // active态图标
},
{
status: 'step2',
value: '进度2',
isActived: false, // 未到达该状态
deActivedIcon: 'weixuanzhong',
activedIcon: 'gouxuan',
},
{
status: 'step3',
value: '进度3',
isActived: false,
deActivedIcon: 'weixuanzhong',
activedIcon: 'gouxuan',
},
{
status: 'step4',
value: '进度4',
isActived: false,
deActivedIcon: 'weixuanzhong',
activedIcon: 'gouxuan',
},
{
status: 'step5',
value: '进度5',
isActived: false,
deActivedIcon: 'weixuanzhong',
activedIcon: 'gouxuan',
},
{
status: 'step6',
value: '进度6',
isActived: false,
deActivedIcon: 'weixuanzhong',
activedIcon: 'gouxuan',
},
],
goStatus: 'step1', // 主动滚动到某个元素
},
methods: {
// 处理进度条数据
// 当前进度 一般会从接口获取到,将当前进度及之前的节点标记为active态
// 比如传入step4,显示效果如图2
handelSteps(step) {
// 获取当前节点在数组中的位置
const ind = this.data.statusEnum.findIndex(val => val.status === step)
// 容错
if (ind >= 0) {
let data = JSON.parse(JSON.stringify(this.data.statusEnum))
// ind及之前的节点标记为active
for (let i = 0; i <= ind; i++) {
data[i].isActived = true
}
const { status } = this.data.statusEnum[ind]
this.setData({
statusEnum: data,
goStatus: status, // 主动滚动到当前最新active节点
})
}
},
}
- wxss
/* scroll-view 样式 */
.step-list {
display: flex;
align-items: flex-start;
flex-wrap: nowrap;
background-color: aliceblue;
padding: 32rpx 0;
margin-top: 28rpx;
}
.step-con {
font-size: 28rpx;
display: flex;
}
/* ---- line样式 */
/* 非active态 */
.deactived-line {
width: 40rpx;
height: 0rpx;
border: 2rpx dashed #DDDDDD;
margin-top: 24rpx;
}
/* active态 */
.actived-line {
width: 40rpx;
height: 0rpx;
border: 2rpx dashed #409EFF;
margin-top: 24rpx;
}
/* iconfont 样式 */
.step-iconfont {
margin: 0rpx 28rpx;
font-size: 48rpx;
/* 非active */
color: #999;
}
/* active态 */
.icon-gouxuan {
color: #409EFF;
}
/* 状态文案 */
.step-tips {
height: 34rpx;
font-size: 24rpx;
line-height: 34rpx;
font-weight: 400;
text-align: right;
padding-top: 12rpx;
padding-right: 20rpx;
}
.actived-tips {
color: #409EFF;
}
.deactived-tips {
color: #999;
}