<template>
	<view class="slider-selector-container">
		<!-- 可选：显示当前选中值 -->
		<view class="slider-value" v-if="showValue">{{ currentValue }}</view>
		<!-- 滑块轨道（增加唯一标识用于选择器查询） -->
		<view class="slider-track" id="sliderTrack" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd">
			<!-- 已选中轨道 -->
			<!-- <view class="slider-track-active" :style="{ width: activeWidth + 'px' }"></view> -->
			<!-- 滑块按钮 -->
			<view class="slider-handle" :style="{ left: activeLeft + 'px' }"></view>
		</view>
	</view>
</template>

<script>
export default {
	name: "SliderSelector",
	props: { 
		// 最小值（默认0）
		min: {
			type: Number,
			default: 0,
		},
		// 最大值（默认100）
		max: {
			type: Number,
			default: 100,
		},
		// 步长（默认1）
		step: {
			type: Number,
			default: 1,
		},
		// 初始值
		value: {
			type: Number,
			default: 0,
		},
		// 是否显示当前值
		showValue: {
			type: Boolean,
			default: true,
		},
	},
	data() {
		return {
			trackWidth: 0, // 轨道宽度
			trackRect: null, // 轨道的位置信息（缓存，避免频繁查询）
			currentValue: this.value, // 当前选中值
			activeLeft: 0, // 滑块左侧偏移量
			activeWidth: 0, // 已选中轨道宽度
			isDragging: false, // 是否正在拖动
		};
	},
	watch: {
		// 监听外部传入的value变化
		value(newVal) {
			if (newVal !== this.currentValue) {
				this.currentValue = newVal;
				this.calcHandlePosition();
			}
		},
	},
	mounted() {
		// 初始化获取轨道信息
		this.$nextTick(() => {
			this.getTrackInfo().then(() => {
				this.calcHandlePosition();
			});
		});
	},
	methods: {
		/**
		 * 封装：通过createSelectorQuery获取轨道的尺寸和位置信息（核心优化点）
		 * @returns {Promise} 轨道信息Promise
		 */
		getTrackInfo() {
			return new Promise((resolve) => {
				// 创建选择器，绑定当前组件实例
				const query = uni.createSelectorQuery().in(this);
				query
					.select("#sliderTrack")
					.boundingClientRect((rect) => {
						if (rect) {
							this.trackWidth = rect.width; // 轨道宽度
							this.trackRect = rect; // 缓存轨道的位置信息（left/top/width/height）
						}
						resolve();
					})
					.exec();
			});
		},

		/**
		 * 计算滑块位置（根据当前值）
		 */
		calcHandlePosition() {
			if (!this.trackWidth) return;
			// 计算值的比例
			const ratio = (this.currentValue - this.min) / (this.max - this.min);
			// 计算滑块偏移量（限制0~trackWidth）
			this.activeLeft = Math.max(0, Math.min(this.trackWidth, ratio * this.trackWidth));
			this.activeWidth = this.activeLeft;
		},

		/**
		 * 计算当前值（根据滑块位置）
		 * @param {Number} left 滑块相对于轨道的左侧偏移量
		 * @returns {Number} 按步长修正后的值
		 */
		calcCurrentValue(left) {
			// 计算比例
			const ratio = left / this.trackWidth;
			// 计算原始值
			let val = this.min + ratio * (this.max - this.min);
			// 按步长取整
			val = Math.round(val / this.step) * this.step;
			// 限制值在min~max之间
			val = Math.max(this.min, Math.min(this.max, val));
			return val;
		},

		/** 
		 * 触摸开始：缓存轨道位置，标记拖动状态
		 */
		handleTouchStart(e) {
			this.isDragging = true;
			// 实时获取最新的轨道位置（防止页面滚动后位置变化）
			this.getTrackInfo();
			// 阻止事件穿透和默认行为
			e.preventDefault();
		},

		/**
		 * 触摸移动：通过缓存的轨道信息计算滑块位置
		 */
		handleTouchMove(e) {
			if (!this.isDragging || !this.trackRect || !this.trackWidth) return;

			// 获取触摸点的绝对X坐标
			const touchX = e.touches[0].clientX;
			// 计算触摸点相对于轨道左侧的偏移量（核心：用缓存的trackRect，非直接DOM操作）
			let relativeX = touchX - this.trackRect.left;
			// 限制偏移量在轨道范围内（0 ~ 轨道宽度）
			relativeX = Math.max(0, Math.min(this.trackWidth, relativeX));

			// 更新滑块位置和当前值
			this.activeLeft = relativeX;
			this.activeWidth = relativeX;
			this.currentValue = this.calcCurrentValue(relativeX);
			// 实时触发值变化事件
			this.$emit("change", this.currentValue);
		},

		/**
		 * 触摸结束：重置拖动状态，触发确认事件
		 */
		handleTouchEnd() {
			this.isDragging = false;
			// 触发确认事件（可选）
			this.$emit("confirm", this.currentValue);
		},
	},
};
</script>

<style scoped lang="scss">
.slider-selector-container {
	width: 65vw;
	padding: 0rpx 16rpx 20rpx 16rpx;
	box-sizing: border-box;
}

.slider-track {
	position: relative;
	width: 100%;
	height: 12rpx;
	background-color: #e5e7eb;
	border-radius: 6rpx;
	touch-action: none; /* 禁用默认触摸行为，提升流畅度 */
}

.slider-track-active {
	position: absolute;
	left: 0;
	top: 0;
	height: 100%;
	background-color: #1890ff;
	border-radius: 6rpx;
}

.slider-handle {
	position: absolute;
	top: 50%;
	transform: translate(-50%, -50%);
	width: 40rpx;
	height: 40rpx;
	background-color: #fff;
	border: 4rpx solid #1890ff;
	border-radius: 50%;
	box-shadow: 0 2rpx 8rpx rgba(24, 144, 255, 0.3);
	z-index: 10;
}

.slider-value {
	margin-bottom: 16rpx;
	font-size: 28rpx;
	color: #333;
	text-align: center;
}
</style>
