














export type GET_MOVE_DIRECTION_INFO = { moveX: number; moveY: number; }; export type GET_MOVE_DIRECTION = { dom?: string | Element; notEdge?: boolean | null; edgeStop?: boolean | null; /** 为 true 时 callback 第二个参数返回额外信息 */ otherInfo?: boolean | null; callback: (direction: string, info?: GET_MOVE_DIRECTION_INFO) => void; }; /** * @Function 获取指定 dom 的 touchmove 方向 * @props { * dom: 指定 dom(选择器或元素) * notEdge: 不达到边缘就触发回调,默认 false * edgeStop: 到达边缘时是否禁止橡皮筋效果,默认 false * otherInfo: 是否返回额外信息,默认 false * callback: 回调函数,返回方向;otherInfo 为 true 时额外返回 { moveX, moveY } * } */ export class GetMoveDirection { startX: number; startY: number; dom: Element | Document | null; props: GET_MOVE_DIRECTION; private listenerOptions: AddEventListenerOptions; constructor(props: GET_MOVE_DIRECTION) { this.startX = 0; this.startY = 0; if (!props?.dom) { this.dom = document; } else if (typeof props.dom === "string") { this.dom = document?.querySelector(props.dom); } else { this.dom = props.dom; } this.removeAllListent = this.removeAllListent.bind(this); this.listenTouchstart = this.listenTouchstart.bind(this); this.listenTouchmove = this.listenTouchmove.bind(this); this.props = props; // notEdge:捕获阶段,避免子元素 stopPropagation 拦掉 callback // edgeStop:passive:false,才能在边缘 preventDefault 禁用橡皮筋效果 this.listenerOptions = { capture: !!props?.notEdge, passive: !props?.edgeStop, }; this.dom?.addEventListener( "touchstart", this.listenTouchstart, this.listenerOptions ); this.dom?.addEventListener( "touchmove", this.listenTouchmove, this.listenerOptions ); } private getScrollDom(): HTMLElement | null { if (!this.dom) return null; return this.dom instanceof Document ? document.documentElement : (this.dom as HTMLElement); } private isAtLeftEdge(dom: HTMLElement) { return dom.scrollLeft === 0; } private isAtRightEdge(dom: HTMLElement) { return ( Math.ceil(dom.scrollLeft + dom.offsetWidth) >= dom.scrollWidth && Math.ceil(dom.scrollLeft + dom.clientWidth) >= dom.scrollWidth ); } private isAtTopEdge(dom: HTMLElement) { return dom.scrollTop === 0; } private isAtBottomEdge(dom: HTMLElement) { return ( Math.ceil(dom.scrollTop + dom.offsetHeight) >= dom.scrollHeight && Math.ceil(dom.scrollTop + dom.clientHeight) >= dom.scrollHeight ); } private applyEdgeStop(ev: TouchEvent, atEdge: boolean, axis: "x" | "y") { if (!this.props?.edgeStop || !atEdge) return; ev.cancelable && ev.preventDefault(); if (axis === "y") { ev.stopPropagation(); } } private emitDirection(direction: string, info: GET_MOVE_DIRECTION_INFO) { if (this.props?.otherInfo) { this.props.callback(direction, info); } else { this.props.callback(direction); } } listenTouchstart(ev: any) { this.startX = ev?.changedTouches?.[0]?.pageX; this.startY = ev?.changedTouches?.[0]?.pageY; } listenTouchmove(ev: any) { const moveEndX = ev?.changedTouches?.[0]?.pageX; const moveEndY = ev?.changedTouches?.[0]?.pageY; const moveX = moveEndX - this.startX; const moveY = moveEndY - this.startY; const _dom = this.getScrollDom(); if (!_dom) return; const absX = Math.abs(moveX); const absY = Math.abs(moveY); const info: GET_MOVE_DIRECTION_INFO = { moveX, moveY }; // 向右拖拽 if (absX > absY && moveX > 0) { const atEdge = this.isAtLeftEdge(_dom); if (this.props?.notEdge || atEdge) { this.emitDirection("right", info); } this.applyEdgeStop(ev, atEdge, "x"); } // 向左拖拽 if (absX > absY && moveX < 0) { const atEdge = this.isAtRightEdge(_dom); if (this.props?.notEdge || atEdge) { this.emitDirection("left", info); } this.applyEdgeStop(ev, atEdge, "x"); } // 向下拖拽 if (absY > absX && moveY > 0) { const atEdge = this.isAtTopEdge(_dom); if (this.props?.notEdge || atEdge) { this.emitDirection("down", info); } this.applyEdgeStop(ev, atEdge, "y"); } // 向上拖拽 if (absY > absX && moveY < 0) { const atEdge = this.isAtBottomEdge(_dom); if (this.props?.notEdge || atEdge) { this.emitDirection("up", info); } this.applyEdgeStop(ev, atEdge, "y"); } } removeAllListent() { this.dom?.removeEventListener( "touchstart", this.listenTouchstart, this.listenerOptions ); this.dom?.removeEventListener( "touchmove", this.listenTouchmove, this.listenerOptions ); } }
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。