uniapp+vue+css手写步骤条组件

概要

首先看效果

技术名词解释

  • uniapp
  • uni组件

技术细节

首先看需求是步骤条,然后看组件中没有自己想要的步骤条,那么就的自己去写

一、HTML部分

<template>
	<view class="mainStepOut">
		<view class="stepOut">
			<ul class="stepul">

				<li class="stepItem">
					<!-- 大圈部分 -->
					<view v-for="(item,index) in list" :key="index">

						<!-- 小圈部分 -->
						<view class="step1" v-if="item.step.length>0" v-for="(item1,index1) in item.step" :key="index1">
							<!-- 此处为小圆圈 -->
							<view :class="index1 === 0 ?(index===0?'iconSmall active':'iconSmall'):'iconSmall'"></view>
							<!-- 模拟步骤条连接线(判断列表到最后一项后把线隐藏) -->
							<view class="line" :style="'height:'+stepnewheight[index1]+'px'"
								v-if="index !== list.length - 1 && item.title1!==''">
							</view>
							<!-- 主题内容 -->
							<view class="stepStatus1" :id="'stepStatus1'+index1">
								<view :class="index1 === 0 ?(index===0?'titlecolor':'title'):'title'">
									<text>{{item1.title}}</text>
									<text>{{item1.date}}</text>
								</view>
								<view class="annotation">
									<view class="item_person" v-html="item1.content">
										<!-- {{item1.content}} -->
									</view>
								</view>
							</view>
						</view>

						<view class="step1" v-if="item.title1!==''">
							<!-- 此处为圆圈 -->
							<view :class="item.step.length!==0?'icon':(index == 0 ?'icon1':'icon')"></view>
							<!-- 模拟步骤条连接线(判断列表到最后一项后把线隐藏) -->
							<view class="line" :style="'height:'+newheight[index]+'px'"
								v-if="index !== list.length - 1">
							</view>
							<!-- 主题内容 -->
							<view class="stepStatus" :id="'stepStatus'+index">
								<view :class="item.step.length!==0 ? 'title':(index == 0 ?'titlecolor':'title')">
									<view>{{item.title1}}</view>
									<text v-if="item.title2">{{item.title2}}</text>
									<text>{{item.date}}</text>
								</view>
								<view class="annotation">
									<view class="item_person" v-html="item.content">
									</view>
								</view>
							</view>
						</view>
					</view>
				</li>
			</ul>
		</view>
	</view>

</template>

二、CSS部分

<style lang="scss" scoped>
	.mainStepOut{
		height: 100%;
		overflow-y: auto;
	}
	.stepOut {
		height: 100%;
		padding-top: 40rpx;
		width: 100%;
		display: flex;
		justify-content: space-between;

		.stepul {
			list-style: none;
			width: 100%;
			margin-left: -20rpx;
			.stepItem {
				width: 100%;
				font-size: 32rpx;
				position: relative;
				border-left: #d7d7d7;

				// display: flex;
				.step1 {
					display: flex;
					width: 100%;
					// height: 200rpx;

					font-size: 32rpx;
					position: relative;
					border-left: #d7d7d7;
				}

				.icon {
					width: 32rpx;
					height: 32rpx;
					flex: 0 0 32rpx;
					border-radius: 50%;
					background: #fff;
					border: 4rpx solid #d7d7d7;
					position: relative;
					z-index: 888;
				}

				.icon1 {
					width: 38rpx;
					height: 38rpx;
					border-radius: 50%;
					flex: 0 0 38rpx;
					right: 1.5px;
					border: 4rpx solid #2E88FF;
					position: relative;
					z-index: 888;
					background-color: #fff;
				}

				.icon1:before {
					content: "";
					position: absolute;
					top: 5rpx;
					left: 5rpx;
					width: calc(100% - 8rpx);
					height: calc(100% - 8rpx);
					background-color: #2E88FF;
					border-radius: 50%;
					flex: 0 0 calc(100% - 8rpx);
				}

				.iconSmall {
					width: 21rpx;
					height: 21rpx;
					border-radius: 50%;
					flex: 0 0 21rpx;
					background: #fff;
					// border: 4rpx solid #d7d7d7;
					position: relative;
					left: 2.8px;
					background: #808080;
					z-index: 888;
					margin-right: 10rpx;
				}

				.active {
					background-color: #2E88FF;
					border: 0;
				}

				.line {
					position: absolute;
					top: 12rpx;
					// left: 13rpx;
					left: 14rpx;
					width: 4rpx;
					// height: 200rpx;
					background-color: #e2e2e2;
					z-index: 111;
				}

				.stepStatus {
					width: 100%;
					padding: 0 25rpx;
					background: #FAFAFA;
					margin-bottom: 26rpx;
					margin-left: 15rpx;
					margin-right: 15rpx;
					padding-top: 10rpx;
					margin-top: -16rpx;
					padding-bottom: 10rpx;
					border-radius: 18rpx;

					.annotation {
						font-size: 25rpx;
						color: #b0b0b0;
					}
				}

				.stepStatus1 {
					width: 100%;
					padding: 0 25rpx;
					background: #FAFAFA;
					margin-bottom: 26rpx;
					margin-left: 15rpx;
					margin-right: 15rpx;
					padding-top: 10rpx;
					margin-top: -16rpx;
					padding-bottom: 10rpx;
					border-radius: 18rpx;

					.annotation {
						font-size: 25rpx;
						color: #b0b0b0;
					}
				}

				// 未进行
				.title {
					display: flex;
					color: #808080;
					margin-bottom: 10rpx;

					view {
						font-size: 30rpx;
						// font-weight: 700;
						margin-right: 18rpx;
					}

					text {
						font-size: 25rpx;
						display: flex;
						flex-direction: column-reverse;
						justify-self: end;
						margin-right: 20rpx;
					}
				}

				// 已进行
				.titlecolor {
					display: flex;
					color: #2E88FF;
					margin-bottom: 10rpx;

					view {
						color: #2E88FF;
						font-size: 30rpx;
						// font-weight: 700;
						margin-right: 18rpx;
					}

					text {
						font-size: 25rpx;
						display: flex;
						flex-direction: column-reverse;
						justify-self: end;
						margin-right: 20rpx;
					}
				}
			}
		}
	}
</style>

因为有小圈还有大圈所有上面的主体部分的进行判断,很好理解的上面都有注释,当你的数组长度最大时就不显示线条,反之显示

现在几乎实现了整体部分,但是bug出现了,就是你的部分如果高的话就会把下面部分挤出去,线条就不能正常链接了,这个问题怎么解决呢!!!别着急看下面

三、bug问题解决

咱们可以通过uniapp中的Api进行判断它的高度进行给线段设置高度(uni.createSelectorQuery)

uni.createSelectorQuery()

返回一个 SelectorQuery 对象实例。可以在这个实例上使用 select 等方法选择节点,并使用 boundingClientRect 等方法选择需要查询的信息。

Tips:

  • 使用 uni.createSelectorQuery() 需要在生命周期 mounted 后进行调用。
  • 默认需要使用到 selectorQuery.in 方法。
measureViewHeight() {
				for (let i = 0; i < this.list.length; i++) {
					uni.createSelectorQuery()
						.in(this)
						.select(`#stepStatus${i}`)
						.boundingClientRect(rect => {
							// console.log(`Div1的高度为:${rect.height}px`);
							let sum = rect.height + 9
							this.newheight.push(sum)
						})
						.selectViewport()
						.scrollOffset()
						.exec();
				}
				for (let i = 0; i < this.list.length; i++) {
					for (let j = 0; j < this.list[i].step.length; j++) {
						uni.createSelectorQuery()
							.in(this)
							.select(`#stepStatus1${j}`)
							.boundingClientRect(rect => {
								// console.log(`Div的高度为:${rect.height}px`);
								let sum = rect.height + 9
								this.stepnewheight.push(sum)
							})
							.selectViewport()
							.scrollOffset()
							.exec();
					}

				}
			},

重新命名两个数组进行存储主体的高度,进行在html部分进行循环输出,我为什么在后面加了一个9呢,因为我进行测试输出的高度总比我想要的高度小,所有我给他们固定加了9px。可以根据自己的需求进行加减

<!-- 模拟步骤条连接线(判断列表到最后一项后把线隐藏) -->
<view class="line" :style="'height:'+stepnewheight[index1]+'px'"
								v-if="index !== list.length - 1 && item.title1!==''">
</view>

四、完整代码

<template>
	<view class="mainStepOut">
		<view class="stepOut">
			<ul class="stepul">

				<li class="stepItem">
					<!-- 大圈部分 -->
					<view v-for="(item,index) in list" :key="index">

						<!-- 小圈部分 -->
						<view class="step1" v-if="item.step.length>0" v-for="(item1,index1) in item.step" :key="index1">
							<!-- 此处为小圆圈 -->
							<view :class="index1 === 0 ?(index===0?'iconSmall active':'iconSmall'):'iconSmall'"></view>
							<!-- 模拟步骤条连接线(判断列表到最后一项后把线隐藏) -->
							<view class="line" :style="'height:'+stepnewheight[index1]+'px'"
								v-if="index !== list.length - 1 && item.title1!==''">
							</view>
							<!-- 主题内容 -->
							<view class="stepStatus1" :id="'stepStatus1'+index1">
								<view :class="index1 === 0 ?(index===0?'titlecolor':'title'):'title'">
									<text>{{item1.title}}</text>
									<text>{{item1.date}}</text>
								</view>
								<view class="annotation">
									<view class="item_person" v-html="item1.content">
										<!-- {{item1.content}} -->
									</view>
								</view>
							</view>
						</view>

						<view class="step1" v-if="item.title1!==''">
							<!-- 此处为圆圈 -->
							<view :class="item.step.length!==0?'icon':(index == 0 ?'icon1':'icon')"></view>
							<!-- 模拟步骤条连接线(判断列表到最后一项后把线隐藏) -->
							<view class="line" :style="'height:'+newheight[index]+'px'"
								v-if="index !== list.length - 1">
							</view>
							<!-- 主题内容 -->
							<view class="stepStatus" :id="'stepStatus'+index">
								<view :class="item.step.length!==0 ? 'title':(index == 0 ?'titlecolor':'title')">
									<view>{{item.title1}}</view>
									<text v-if="item.title2">{{item.title2}}</text>
									<text>{{item.date}}</text>
								</view>
								<view class="annotation">
									<view class="item_person" v-html="item.content">
									</view>
								</view>
							</view>
						</view>
					</view>
				</li>
			</ul>
		</view>
	</view>

</template>

<script>
	import Api from '@/untils/api.js'
	export default {
		data() {
			return {
				list: [], //模拟数据
				newheight: [],
				stepnewheight: []
			};
		},
		created() {

		},
		mounted() {
			this.getProgressByAccountNo()

			this.$nextTick(() => {
				setTimeout(() => {
					this.measureViewHeight()
				}, 320)
			})
		},
		methods: {
			measureViewHeight() {
				for (let i = 0; i < this.list.length; i++) {
					uni.createSelectorQuery()
						.in(this)
						.select(`#stepStatus${i}`)
						.boundingClientRect(rect => {
							// console.log(`Div1的高度为:${rect.height}px`);
							let sum = rect.height + 9
							this.newheight.push(sum)
						})
						.selectViewport()
						.scrollOffset()
						.exec();
				}
				for (let i = 0; i < this.list.length; i++) {
					for (let j = 0; j < this.list[i].step.length; j++) {
						uni.createSelectorQuery()
							.in(this)
							.select(`#stepStatus1${j}`)
							.boundingClientRect(rect => {
								// console.log(`Div的高度为:${rect.height}px`);
								let sum = rect.height + 9
								this.stepnewheight.push(sum)
							})
							.selectViewport()
							.scrollOffset()
							.exec();
					}

				}
			},
			// 进度接口
			getProgressByAccountNo() {
				//接口
			}
		}
	};
</script>

<style lang="scss" scoped>
	.mainStepOut{
		height: 100%;
		overflow-y: auto;
	}
	.stepOut {
		height: 100%;
		padding-top: 40rpx;
		width: 100%;
		display: flex;
		justify-content: space-between;

		.stepul {
			list-style: none;
			width: 100%;
			margin-left: -20rpx;
			.stepItem {
				width: 100%;
				font-size: 32rpx;
				position: relative;
				border-left: #d7d7d7;

				// display: flex;
				.step1 {
					display: flex;
					width: 100%;
					// height: 200rpx;

					font-size: 32rpx;
					position: relative;
					border-left: #d7d7d7;
				}

				.icon {
					width: 32rpx;
					height: 32rpx;
					flex: 0 0 32rpx;
					border-radius: 50%;
					background: #fff;
					border: 4rpx solid #d7d7d7;
					position: relative;
					z-index: 888;
				}

				.icon1 {
					width: 38rpx;
					height: 38rpx;
					border-radius: 50%;
					flex: 0 0 38rpx;
					right: 1.5px;
					border: 4rpx solid #2E88FF;
					position: relative;
					z-index: 888;
					background-color: #fff;
				}

				.icon1:before {
					content: "";
					position: absolute;
					top: 5rpx;
					left: 5rpx;
					width: calc(100% - 8rpx);
					height: calc(100% - 8rpx);
					background-color: #2E88FF;
					border-radius: 50%;
					flex: 0 0 calc(100% - 8rpx);
				}

				.iconSmall {
					width: 21rpx;
					height: 21rpx;
					border-radius: 50%;
					flex: 0 0 21rpx;
					background: #fff;
					// border: 4rpx solid #d7d7d7;
					position: relative;
					left: 2.8px;
					background: #808080;
					z-index: 888;
					margin-right: 10rpx;
				}

				.active {
					background-color: #2E88FF;
					border: 0;
				}

				.line {
					position: absolute;
					top: 12rpx;
					// left: 13rpx;
					left: 14rpx;
					width: 4rpx;
					// height: 200rpx;
					background-color: #e2e2e2;
					z-index: 111;
				}

				.stepStatus {
					width: 100%;
					padding: 0 25rpx;
					background: #FAFAFA;
					margin-bottom: 26rpx;
					margin-left: 15rpx;
					margin-right: 15rpx;
					padding-top: 10rpx;
					margin-top: -16rpx;
					padding-bottom: 10rpx;
					border-radius: 18rpx;

					.annotation {
						font-size: 25rpx;
						color: #b0b0b0;
					}
				}

				.stepStatus1 {
					width: 100%;
					padding: 0 25rpx;
					background: #FAFAFA;
					margin-bottom: 26rpx;
					margin-left: 15rpx;
					margin-right: 15rpx;
					padding-top: 10rpx;
					margin-top: -16rpx;
					padding-bottom: 10rpx;
					border-radius: 18rpx;

					.annotation {
						font-size: 25rpx;
						color: #b0b0b0;
					}
				}

				// 未进行
				.title {
					display: flex;
					color: #808080;
					margin-bottom: 10rpx;

					view {
						font-size: 30rpx;
						// font-weight: 700;
						margin-right: 18rpx;
					}

					text {
						font-size: 25rpx;
						display: flex;
						flex-direction: column-reverse;
						justify-self: end;
						margin-right: 20rpx;
					}
				}

				// 已进行
				.titlecolor {
					display: flex;
					color: #2E88FF;
					margin-bottom: 10rpx;

					view {
						color: #2E88FF;
						font-size: 30rpx;
						// font-weight: 700;
						margin-right: 18rpx;
					}

					text {
						font-size: 25rpx;
						display: flex;
						flex-direction: column-reverse;
						justify-self: end;
						margin-right: 20rpx;
					}
				}
			}
		}
	}
</style>

接口数据结构

小结

如果感觉还不错的话可以关注博主哦,会持续更新的,谢谢~谢谢

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
UniApp 是一个基于 Vue.js 的跨平台框架,可以用于开发多个平台的应用程序。如果你想要自定义竖向的步骤,可以通过使用 Vue.jsCSS 来实现。 首先,你可以创建一个组件来表示每个步骤,例如 Step.vue: ```vue <template> <div :class="{'step': true, 'active': isActive}">{{ index }}</div> </template> <script> export default { props: { index: { type: Number, required: true }, isActive: { type: Boolean, default: false } } } </script> <style scoped> .step { width: 50px; height: 50px; border-radius: 50%; line-height: 50px; text-align: center; background-color: #ccc; } .active { background-color: #ff0000; color: #fff; } </style> ``` 然后,在你的页面中使用这个组件来创建竖向的步骤,例如 Steps.vue: ```vue <template> <div class="steps"> <step v-for="(step, index) in steps" :key="index" :index="index + 1" :is-active="currentStep === index + 1" /> </div> </template> <script> import Step from '@/components/Step.vue' export default { components: { Step }, data() { return { steps: ['Step 1', 'Step 2', 'Step 3'], currentStep: 1 } } } </script> <style scoped> .steps { display: flex; flex-direction: column; } </style> ``` 在上面的例子中,使用了一个数组来定义步骤的文本内容,然后通过 v-for 指令和 Step 组件来渲染每个步骤。通过给 Step 组件传递 `:is-active` 属性来判断当前步骤是否为激活状态。 这样,你就可以在 UniApp 中自定义竖向的步骤了。根据你的需要,你可以根据具体的样式要求进行调整和扩展。希望对你有所帮助!如果你对这方面还有其他问题,可以继续问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值