首页 前端知识 uniapp vue css手写步骤条组件

uniapp vue css手写步骤条组件

2024-07-30 22:07:17 前端知识 前端哥 488 182 我要收藏

文章目录

    • 概要
    • 技术名词解释
    • 技术细节
    • 小结

概要

首先看效果

技术名词解释

  • 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>

接口数据结构

小结

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

转载请注明出处或者链接地址:https://www.qianduange.cn//article/14570.html
标签
评论
发布的文章

AE、Lottie、JSON简单介绍

2024-08-12 10:08:42

VSCode配置settings.json

2024-08-12 10:08:42

JSON 格式说明

2024-08-12 10:08:34

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!