Просмотр исходного кода

优化权益页面滑块选组件,兼容H5鼠标点击松开事件触发条件

@dongkboy 4 недель назад
Родитель
Сommit
12d9f0f579
1 измененных файлов с 59 добавлено и 9 удалено
  1. 59 9
      components/uni-tianzai-slider-range/uni-tianzai-slider-range.vue

+ 59 - 9
components/uni-tianzai-slider-range/uni-tianzai-slider-range.vue

@@ -34,11 +34,12 @@
 				</view>
 
 				<!-- 第二个滑块 -->
-				<view class="block-item" v-if="secondBlock.show" :style="{
-						left: getSecondBlockPosition,
-						zIndex: secondBlock.zIndex
-					}" data-sort="secondBlock" @touchstart.stop.prevent="onTouchStart" @touchmove.stop.prevent="onTouchMove"
-					@touchend.stop.prevent="onTouchEnd">
+					<view class="block-item" v-if="secondBlock.show" :style="{
+							left: getSecondBlockPosition,
+							zIndex: secondBlock.zIndex
+						}" data-sort="secondBlock" @touchstart.stop.prevent="onTouchStart" @touchmove.stop.prevent="onTouchMove"
+						@touchend.stop.prevent="onTouchEnd" @mousedown.stop="onTouchStart" @mousemove.stop="onTouchMove"
+						@mouseleave.stop="onTouchEnd" @mouseup.stop="onTouchEnd">
 
 					<!-- 非微信小程序插槽 -->
 					<!-- #ifndef MP-WEIXIN -->
@@ -181,8 +182,10 @@
 					show: true,
 					zIndex: 2,
 				},
-				// 动中
+				// 动中
 				dragging: '',
+				// H5 端拖动锁,防止 mouseup/mouseleave 重复触发 end,以及松手后再次移入时还在滑动
+				isDragging: false,
 				// 刻度线设置
 				scaleInfo: {
 					show: true,
@@ -294,7 +297,10 @@
 			 * @param {Event} e 触摸事件对象
 			 */
 			onTouchStart(e) {
+				// 如果上一次拖动未结束,不响应新的 mousedown(避免 H5 端 mouseup 之后又 mousedown 混乱)
+				if (this.isDragging) return
 				if (this.disabled) return
+				this.isDragging = true
 				// 设置当前拖动的滑块
 				this.dragging = e.currentTarget.dataset.sort
 				// 调整z-index,确保当前拖动的滑块在上方
@@ -302,7 +308,7 @@
 					this.firstBlock.zIndex = this.secondBlock.zIndex + 1 :
 					this.secondBlock.zIndex = this.firstBlock.zIndex + 1
 				// 记录开始位置和初始值
-				this.startDragPostion = e.changedTouches ? e.changedTouches[0].pageX : e.pageX
+				this.startDragPostion = (e.changedTouches && e.changedTouches[0]) ? e.changedTouches[0].pageX : (e.pageX || 0)
 				this.startValue = e.currentTarget.dataset.sort == 'firstBlock' ? this.firstValue : this.secondValue
 				// 触发开始事件
 				this.$emit('start', {
@@ -319,6 +325,8 @@
 			 */
 			onTouchMove(e) {
 				if (this.disabled) return
+				// 拖动已结束(mouseup/mouseleave 后又移入),直接拦截
+				if (!this.isDragging) return
 				this.onDrag(e)
 			},
 
@@ -327,6 +335,9 @@
 			 * @param {Event} e 触摸事件对象
 			 */
 			onTouchEnd(e) {
+				// 拖动已结束过(mouseup 和 mouseleave 都会触发),避免重复发 end
+				if (!this.isDragging) return
+				this.isDragging = false
 				this.dragging = ''
 				if (this.disabled) return
 				this.onDrag(e, true)
@@ -338,13 +349,47 @@
 			 * @param {boolean} end 是否结束拖动
 			 */
 			onDrag(e, end = false) {
-				let pageX = e.changedTouches ? e.changedTouches[0].pageX : e.pageX
+				// 兼容 MouseEvent、TouchEvent、以及 e 为 null 的情况
+				let pageX = 0
+				if (e && e.changedTouches && e.changedTouches[0]) {
+					pageX = e.changedTouches[0].pageX
+				} else if (e && typeof e.pageX === 'number') {
+					pageX = e.pageX
+				}
+				// 如果 end 时无法拿到 pageX,使用最后记录的 startDragPostion(也就是不移动,只确认 end)
+				if (end && pageX === 0 && this.startDragPostion) {
+					pageX = this.startDragPostion
+				}
+				// 兜底 e.currentTarget,取当前正在拖动的滑块
+				let sort = (e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.sort) || this.dragging
 				let view = uni.createSelectorQuery().in(this).select('.block-bar')
 				view.boundingClientRect(data => {
+					// DOM 还没渲染好时 data 可能为 null,做兜底
+					if (!data || !data.width) {
+						if (end) {
+							this.$emit('end', {
+								block: sort,
+								value: this.startValue,
+								values: [Math.min(this.firstValue, this.secondValue), Math.max(this.firstValue, this.secondValue)]
+							})
+						}
+						return
+					}
 					// 计算拖动距离对应的数值变化
 					let diff = ((pageX - this.startDragPostion) / data.width) * (this.max - this.min)
+					// 如果 diff 是 NaN,跳过这次更新
+					if (isNaN(diff)) {
+						if (end) {
+							this.$emit('end', {
+								block: sort,
+								value: this.startValue,
+								values: [Math.min(this.firstValue, this.secondValue), Math.max(this.firstValue, this.secondValue)]
+							})
+						}
+						return
+					}
 					// 更新值
-					this.onUpdateValue(this.startValue + diff, e.currentTarget.dataset.sort, end)
+					this.onUpdateValue(this.startValue + diff, sort, end)
 				}).exec()
 			},
 
@@ -355,6 +400,11 @@
 			 * @param {boolean} end 是否结束拖动
 			 */
 			onUpdateValue(value, sort, end = false) {
+				// 入口 NaN 防护:如果 value 是 NaN,降级为当前滑块已有值
+				if (isNaN(value)) {
+					value = sort == 'firstBlock' ? this.firstValue : this.secondValue
+					if (isNaN(value)) value = this.min
+				}
 				// 限制值在范围内
 				if (value < this.min) value = this.min
 				if (value > this.max) value = this.max