uniapp 滚动尺

scale组件代码(部分class样式使用到了uview1.0的样式)

html 复制代码
<template>
	<view>
		<view class="scale">
			<view class="pointer u-flex-col u-col-center">
				<u-icon name="arrow-down-fill" size="26" color="#33B4C2"></u-icon>
			</view>
			<view class="ruler">
				<scroll-view class="scroll" :scroll-x="true" :scrollLeft="scrollLeft" @scroll="scaleScroll"
					@touchstart="touchstart" @touchend="touchend">
					<view class="u-col-top" style="display: inline-flex;padding: 0 calc(50%);">
						<template v-for="(item,index) in scale">
							<view :class="['line',item%10==0?'int':(item%5==0?'middle':'')]"
								:style="{width: `${width}rpx`}" >
								<view class="value" v-if="item%10==0">
									<text>{{item/10}}</text>
								</view>
							</view>
						</template>
					</view>
				</scroll-view>
			</view>
		</view>
	</view>
</template>
javascript 复制代码
<script>
	export default {
		name: 'Scale',
		components: {},
		props: {
			value: {
				type: String,
				default: '0.0'
			},
			// 最小值
			min: {
				type: Number,
				default: 0,
			},
			// 最大值
			max: {
				type: Number,
				default: 100,
			},
			// 每个刻度宽度
			width: {
				type: Number,
				default: 10,
			},
		},
		data() {
			return {
				scrollLeft: 0,//
				left:0,//
				isScroll: true,//用户是否停止操作
				scrollTimer:null,
				manual:false,
				implement:false,//是否还在滚动
			};
		},
		computed: {
			scale() {
				//计算出标尺所有刻度
				let arr = [];
				for (let i = this.min*10; i <= this.max * 10; i++) {
					arr.push(i);
				}
				return arr;
			},
			widthPx(){
				//每个刻度宽度
				return uni.upx2px(this.width);
			}
		},
		created() {
			//数据回显
			let val = parseFloat(this.value);
			if(val<=this.min){
				this.$emit('input',this.min.toFixed(1))
			}else{
				this.scroll()
			}
		},
		methods: {
			//滚动
			scaleScroll(e) {
				
				if(!this.manual){
					return;
				}
				
				//还在滚动中
				this.implement = true;
				
				//获取滚动距离
				let scrollLeft = e.detail.scrollLeft;
				this.left = scrollLeft;
				
				//计算对应值
				let index = (scrollLeft / this.widthPx).toFixed(0);
				let value = (this.scale[parseInt(index)]/10).toFixed(1);
				this.$emit('input', value);
				
				//避免重复执行@scroll
				clearTimeout(this.scrollTimer);
				this.scrollTimer = setTimeout(()=>{
					//判断用户是否已经停止操作
					if(this.isScroll){
						this.scroll()
					}
				},300)
			},
			//开始滚动
			touchstart(e) {
				this.isScroll = false;
				this.manual = true;
			},
			//用户停止操作
			touchend(e) {
				this.isScroll = true;
				this.implement = false;
				//解决scaleScroll已经执行完,但标尺未吸附问题
				setTimeout(()=>{
					//判断是否还在滚动并且是否已经吸附
					if(this.left!=this.scrollLeft&&!this.implement){
						this.scroll()
					}
				},300)
			},
			//标尺吸附
			scroll(){
				//吸附时禁止执行@scaleScroll,防止一直滚动,数据异常
				this.manual = false;
				
				//计算滚动距离
				let index = this.scale.indexOf(parseInt(this.value*10));
				this.scrollLeft = index * this.widthPx;
			}
		},
	};
</script>
css 复制代码
<style lang="scss" scoped>
	.scale {
		width: 100%;

		.pointer {
			position: relative;
			padding-bottom: 12rpx;

			&::after {
				position: absolute;
				z-index: 9;
				top: 38rpx;
				content: '';
				display: block;
				width: 4rpx;
				height: 78rpx;
				background: #33B4C2;
			}
		}

		.ruler {
			height: 114rpx;

			.scroll {
				height: 100%;
				width: 100%;

				::-webkit-scrollbar {
					width: 0;
					height: 0;
					color: transparent;
				}

				.line {
					position: relative;
					height: 36rpx;
					display: flex;
					flex-direction: column;
					align-items: center;
					&:last-child{
						width: 2rpx !important;
					}

					&::after {
						content: '';
						position: absolute;
						display: block;
						width: 2rpx;
						height: 100%;
						top: 0;
						left: 0;
						background: #C1E8ED;
					}

					.value {
						left: -23rpx;
						position: absolute;
						bottom: -48rpx;
						width: 46rpx;
						height: 36rpx;
						font-size: 26rpx;
						font-family: PingFang SC-Regular, PingFang SC;
						font-weight: 400;
						color: #C1C1C1;
						line-height: 36rpx;
						text-align: center;
					}
				}

				.int {
					height: 66rpx;
				}

				.middle {
					height: 50rpx;
				}
			}
		}
	}
</style>

使用方式

javascript 复制代码
<script>
	import Scale from '@/components/Scale/index.vue';
	export default {
		components: {
			Scale
		},
		data() {
			return {
				value:'10.0',
			}
		},
	}
</script>
html 复制代码
<view class="value">
			<text>{{value}}</text>
		</view>
		<scale v-model="value" :width="16"></scale>
css 复制代码
<style lang="scss">
	.value{
		padding: 36rpx 0 20rpx;
		font-size: 36rpx;
		font-family: PingFang SC-Regular, PingFang SC;
		font-weight: 400;
		color: #33B4C2;
		line-height: 50rpx;
		text-align: center;
		&::after{
			content: ' 公斤';
			height: 50rpx;
			font-size: 24rpx;
			font-family: PingFang SC-Regular, PingFang SC;
			font-weight: 400;
			color: #33B4C2;
			line-height: 50rpx;
		}
	}
</style>
相关推荐
尤小小6 分钟前
Vite-SSG 实践:Vue项目预渲染落地完整方案
前端·vue.js
默_笙12 分钟前
🍕 AI 的嘴巴装了水管(上):从"等它说完"到"边说边听"的流式输出指南
前端·javascript
lichenyang45313 分钟前
让 VK 小程序调用 HarmonyOS 原生能力:壳子 SDK 的实现思路
前端
SamChan9022 分钟前
PDF翻译后的格式完整性校验:用Python自动比对译文与原文档的表格与段落结构
开发语言·python·ai·pdf·机器翻译
梨想橙汁23 分钟前
Vue3 组合式 API 深度解析:ref/reactive 响应式,计算属性与侦听器
前端·vue.js
暖焰核心24 分钟前
继承全解——继承、默认成员函数、切片、隐藏与虚继承
java·前端·javascript
by组态30 分钟前
Ricon组态系统API参考手册
前端·后端·物联网
君顾133 分钟前
外卖CPS系统开发实战指南:从架构设计到部署全流程解析
java·开发语言·外卖
前端逗比逗33 分钟前
AI 前端落地实战:SSE 流式输出、断点续传、打字机渲染
前端·webassembly