当前位置: 首页 > article >正文

uniapp自定义圆形滑杆

之前我的一篇文章写的是自定义长方形滑杆,这次客户修改了,让改成圆形的。上代码吧

我这个是在NVUE中运行的代码,其他没有测试,主要是学习与参考,如果不能用,就学习其中的逻辑,主要在边界的处理,我当时也是看着别人的做的,不知道为什么。。。。-。-

78这个数字,是根据宽度和高度进行修改的,是他们的一般多一点,反正调试到中间就好,自己调试看看

<template>
	<view class="slider-container" :style="containerStyle" @touchmove.prevent>
		<view ref="sliderHandle" class="slider-handle" :style="handleStyle" @touchstart="onTouchStart"
			@touchmove.stop="onTouchMove($event)" @touchend="onTouchEnd"></view>
	</view>
</template>

<script>
	export default {
		name: 'SliderControl',

		props: {
			width: {
				type: [Number, String],
				default: 220
			},
			height: {
				type: [Number, String],
				default: 220
			}
		},

		data() {
			return {
				position: {
					x: 78,
					y: 78
				},
				ZeroPoint:{
					x: 78,
					y: 78
				},
				isDragging: false,
				startTouch: null,
				startPosition: null,
				lastUpdate: 0,
				lastEmittedAngle: 0,
				lastEmittedDistance: 0,
				animationTimer: null
			}
		},

		methods: {
			onTouchStart(e) {
				uni.vibrateShort({
					success: () => {},
					fail: (err) => {
						console.error('短振动失败:', err);
					}
				});
				e.stopPropagation();
				if (this.animationTimer) {
					clearTimeout(this.animationTimer);
					this.animationTimer = null;
				}

				const touch = e.touches[0];
				if (!touch) return;

				this.isDragging = true;
				this.startTouch = {
					x: touch.pageX,
					y: touch.pageY
				};
				this.startPosition = {
					x: touch.screenX,
					y: touch.screenY
				};

				this.lastUpdate = Date.now();

			},

			onTouchMove(e) {



				//console.log(e);
				if (!this.isDragging || !this.startTouch) return;
				e.stopPropagation();

				const now = Date.now();
				const timeDiff = now - this.lastUpdate;
				if (timeDiff < 16) return;
				this.lastUpdate = now;

				const touch = e.touches[0];
				if (!touch) return;

				const deltaX = touch.pageX - this.startTouch.x;
				const deltaY = touch.pageY - this.startTouch.y;
				
				
				let powV = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2))
				const maxDistance = Math.min(parseInt(this.width), parseInt(this.height)) / 2 - 25;
				const distance = Math.min(Math.sqrt(deltaX * deltaX + deltaY * deltaY), maxDistance);

				const deltaScX = touch.screenX - this.startPosition.x;
				const deltaScY = touch.screenY - this.startPosition.y;
				
				//console.log(deltaScX,deltaScY)
				
				const distanceSc = Math.sqrt(deltaScX * deltaScX + deltaScY * deltaScY);
				//const distance = Math.min(distanceSc, maxDistance);
				
				
				//超出边界时的处理
				if(distanceSc >= maxDistance)
				{
					var templeft = maxDistance / distanceSc * deltaScX;
					var  temptop = maxDistance / distanceSc * deltaScY;
					
					
					this.position.x = this.ZeroPoint.x + templeft;
					this.position.y = this.ZeroPoint.y + temptop;
					
					
				}else{
					const angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
					
					const targetPos = {
						x: deltaX * (distance / Math.sqrt(deltaX * deltaX + deltaY * deltaY)),
						y: deltaY * (distance / Math.sqrt(deltaX * deltaX + deltaY * deltaY))
					};
					
					const smoothFactor = Math.min(0.08, timeDiff / 250);
					this.position.x = this.position.x + deltaX;
					this.position.y = this.position.y + deltaY;
					//console.log(this.position)
					const roundedAngle = Math.round(angle * 100) / 100;
					const roundedDistance = Math.round((distance / maxDistance) * 100) / 100;
					
					if (Math.abs(roundedAngle - this.lastEmittedAngle) >= 0.01 || Math.abs(roundedDistance - this
							.lastEmittedDistance) >= 0.01) {
						this.lastEmittedAngle = roundedAngle;
						this.lastEmittedDistance = roundedDistance;
						this.$emit('change', {
							angle: roundedAngle,
							distance: roundedDistance
						});
					}
				}
				
			},

			onTouchEnd(e) {
				if (!this.isDragging) return;
				e.stopPropagation();

				this.isDragging = false;
				this.startTouch = null;
				this.startPosition = null;

				const startPos = {
					...this.position
				};
				const startTime = Date.now();
				const duration = 500;

				const easeOutQuart = t => 1 - Math.pow(1 - t, 4);

				const animate = () => {
					const elapsed = Date.now() - startTime;
					if (elapsed >= duration) {
						this.position = { 
							...this.ZeroPoint
						};
						console.log("end")
						this.$emit('change', {
							angle: 0,
							distance: 0
						});
						this.animationTimer = null;
						return;
					}

					const progress = elapsed / duration;
					const easeProgress = easeOutQuart(progress);

					this.position.x = startPos.x + (this.ZeroPoint.x - startPos.x) * easeProgress;
					this.position.y = startPos.y + (this.ZeroPoint.y- startPos.y) * easeProgress;
					console.log(this.position)
					this.animationTimer = setTimeout(animate, 16);
				};

				animate();
			}
		},

		beforeDestroy() {
			if (this.animationTimer) {
				clearTimeout(this.animationTimer);
			}
		},

		computed: {
			containerStyle() {
				return {
					width: typeof this.width === 'number' ? `${this.width}px` : this.width,
					height: typeof this.height === 'number' ? `${this.height}px` : this.height,
					backgroundColor: 'rgba(0, 0, 0, 0.5)',
					borderRadius: '100px',
					position: 'relative',
					overflow: 'hidden'
				}
			},

			handleStyle() {
				return {
					position: 'absolute',
					width: '50px',
					height: '50px',
					backgroundColor: '#FFFFFF',
					borderRadius: '50px',
					transform: `translate(${this.position.x}px, ${this.position.y}px)`,
					top: '50%',
					left: '50%',
					marginLeft: '-25px',
					marginTop: '-25px',
					boxSizing: 'border-box'
				}
			}
		}
	}
</script>

<style>
	.slider-container {
		width: 100%;
		height: 100%;
		position: relative;
		background-color: rgba(255, 255, 255, 0.3);
		border-radius: 50%;
		overflow: hidden;
		/* 确保容器内内容不溢出 */
	}

	.slider-handle {
		position: absolute;
		background-color: #FFFFFF;
		border-radius: 50%;
		box-sizing: border-box;
		/* 确保手柄大小计算正确 */
	}
</style>

父类调用这样的样式:

<template>
	<view :style="{width:screenWidth+'px',height:screenHeight+'px'}" style="position: relative;touch-action: none;">
<view class="noPlayVideo"
			style="position: absolute; right: 50px;bottom: 10px;z-index: 999;" @touchmove.prevent.stop>
			
			<view class="bottomview flexRowCenter" @touchmove.prevent.stop>
				
				
				<!-- 控车 -mode="vertical"-->
			<AllDicrtion mode="vertical" :width="150" :height="150" @change="sliderChange_ver" />



			</view>
		</view>
    </view>
</template>

<script>

	import AllDicrtion from '@/components/all-dirction-hand-shank/index.vue'



	export default {
		components: {
			
			AllDicrtion
        }
    }

</script>
<style>
	.noPlayVideo {
		background-color: #fff;
	}

.bottomview {
		align-items: center;
		text-align: center;
		margin: 4px 3px;

	}

.flexRowCenter {
		display: flex;
		flex-direction: row;
		align-items: center;
	}

</style>


http://www.kler.cn/a/613337.html

相关文章:

  • 社区医疗服务可视化系统+论文源码视频演示
  • 企业数据怎么防泄露?天锐蓝盾筑牢企业网络安全防线
  • 攻破tensorflow,勇创最佳agent(2)---损失(loss) 准确率(accuracy)问题
  • DefogNet 与 TSID-Net:两种单图像去雾方法的对比分析
  • 天气预警API:守护安全的数字防线
  • Nacos Console 模块的作用是什么?是如何与 Server 端交互的?
  • 李宏毅机器学习笔记(1)—机器学习基本概念+深度学习基本概念
  • DBeaver配置postgresql数据库连接驱动
  • TF32 与 FP32 的区别
  • C++设计模式-状态模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析
  • 如何保证LabVIEW软件开发的质量?
  • Vue 的响应式机制未生效——v-model 绑定的冰淇淋输入框值不更新
  • 每日一题之日期统计
  • 多个git账户团队写作
  • Python爬虫如何检测请求频率?
  • DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例6,TableView16_06 分页表格拖拽排序
  • Java制作简单的聊天室(复习)
  • 高精度除法
  • 深入浅出SPI通信协议与STM32实战应用(W25Q128驱动)(理论部分)
  • 重试机制之指针退避策略算法