需求描述:
icon固定在页面左右4px范围,全页面范围内拖动,为避免与小程序顶部胶囊重合,回弹距离顶部200px
问题描述:
- 微信小程序场景:拖动到顶部时,改变x,y值无法回归左右两侧
- alipayHK小程序场景:具有滚动穿透的遗留问题概述 | Taro 文档
- h5场景:会将拖动内容当成自己的父容器,且x,y值监听处理机制有问题
问题排查过程:
- alipayHK小程序的滚动穿透,通过尝试taro给出的两种方案,只有通过修改页面布局解决
- 改变x,y值无法回归左右两侧问题,查询taro库issues,有RN类似issue,但官网暂未修复github.com
- 通过查阅taro源码,查看watchX方法,只有在x值发生变化时,才会更改icon坐标。代码处理方式有问题x值拖动时在同一侧时,不会发生变化,于是拖动icon无法回弹,无监听开始拖动与结束拖动的API,如果贸然修改X值,会触发change事件,导致死循环。
@Watch('x')
watchX (newValue: number | string) {
this.setTransform(parseFloat(`${newValue || 0}`), this.translateY)
}
4. 再查看setTransform源码,发现只有translateX或translateY数字值变化时,会触发change事件,但是WatchX值,可以为number|string,根据vue3 watch的特性,不是全等值会触发watch事件,如果为同一侧,那就字符串数字与数字切换,不会产生死循环,又能改变坐标
watchX (newValue: number | string)
private translateX: number = 0
setTransform = (x: number, y: number, scale?: number, source?: string, noEmitChange?: boolean, emitScale?: boolean) => {
x = Number(x.toFixed(1))
y = Number(y.toFixed(1))
if (this.translateX !== x || this.translateY !== y) {
!noEmitChange && this.onChange.emit({
x: realX,
y: realY,
source
})
}
//...
const transform = `translateX(${x}px) translateY(${y}px) translateZ(0px) scale(${scale})`
this.element.style.transform = transform
this.element.style.webkitTransform = transform
this.translateX = x
this.translateY = y
this.currentScale = scale
//...
}
5. h5将自己当成父容器,查看taro源码,是父容器获取MovableView的时机无法满足需求,在h5中componentDidLoad时机跟平常vue3项目不同,但无法修改taro源码改变运行机制,于是将v-if修改为v-show
/** 子元素集合 */
private views: Array<HTMLElement> = []
componentDidLoad () {
this.viewsChanged()
}
viewsChanged = () => {
this.views = []
const elements = this.element.querySelectorAll('taro-movable-view-core')
Array.from(elements).forEach((element) => {
this.views.push(element)
})
this.updateArea()
}
反思改进:
排查问题强类型语言更简洁直观。