mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
156 lines
4.6 KiB
TypeScript
156 lines
4.6 KiB
TypeScript
import { getComponentSettings } from '@/core/settings'
|
|
|
|
interface Point {
|
|
x: number
|
|
y: number
|
|
}
|
|
interface Position {
|
|
screenX: number
|
|
screenY: number
|
|
clientX: number
|
|
clientY: number
|
|
}
|
|
const isValidMove = (startPoint: Point, currentPoint: Point, minMoveDistance: number) => {
|
|
const x2 = Math.abs(startPoint.x - currentPoint.x) ** 2
|
|
const y2 = Math.abs(startPoint.y - currentPoint.y) ** 2
|
|
return x2 + y2 >= minMoveDistance * minMoveDistance
|
|
}
|
|
const composeMouseEvent = (type: string, position: Position) =>
|
|
new MouseEvent(type, {
|
|
screenX: position.screenX,
|
|
screenY: position.screenY,
|
|
clientX: position.clientX,
|
|
clientY: position.clientY,
|
|
bubbles: true,
|
|
cancelable: true,
|
|
view: unsafeWindow,
|
|
detail: 1,
|
|
})
|
|
// const composeWheelEvent = (startPoint: Point, currentPoint: Point, position: Position) => {
|
|
// return new WheelEvent('wheel', {
|
|
// deltaY: currentPoint.y - startPoint.y,
|
|
// screenX: position.screenX,
|
|
// screenY: position.screenY,
|
|
// clientX: position.clientX,
|
|
// clientY: position.clientY,
|
|
// bubbles: true,
|
|
// cancelable: true,
|
|
// view: unsafeWindow,
|
|
// })
|
|
// }
|
|
type TouchEventHandler = (e: TouchEvent) => void
|
|
interface TouchEventHandlers {
|
|
element: HTMLElement
|
|
touchstart: TouchEventHandler
|
|
touchmove: TouchEventHandler
|
|
touchend: TouchEventHandler
|
|
// [key: string]: any
|
|
}
|
|
const attachedHandlers: TouchEventHandlers[] = []
|
|
const listenerOptions = { passive: false, capture: true }
|
|
/** 触摸拖动选项 */
|
|
export interface TouchMoveOptions {
|
|
/** 最小移动距离(px), 大于这个值才会视为拖动操作 */
|
|
minMoveDistance?: number
|
|
// /** */
|
|
// scroll?: boolean
|
|
}
|
|
/**
|
|
* 为元素启用触摸拖动支持(模拟鼠标事件), 元素本身需要支持用鼠标拖动
|
|
* @param element 目标元素
|
|
* @param options 选项
|
|
*/
|
|
export const enableTouchMove = (element: HTMLElement, options?: TouchMoveOptions) => {
|
|
if (attachedHandlers.some(h => h.element === element)) {
|
|
return
|
|
}
|
|
let startPoint: Point
|
|
// let startTouch: Touch
|
|
let lastTouch: Touch
|
|
let move: boolean
|
|
const minMoveDistance = lodash.get(
|
|
options,
|
|
'minMoveDistance',
|
|
getComponentSettings('touchMiniPlayer').options.touchMoveDistance,
|
|
) as number
|
|
// const scroll = lodash.get(options, 'scroll', false)
|
|
const touchstart = (e: TouchEvent) => {
|
|
if (e.touches.length < 1) {
|
|
return
|
|
}
|
|
const touch = e.touches[0]
|
|
// startTouch = touch
|
|
startPoint = {
|
|
x: touch.clientX,
|
|
y: touch.clientY,
|
|
}
|
|
;(e.target as HTMLElement).dispatchEvent(composeMouseEvent('mousedown', touch))
|
|
}
|
|
element.addEventListener('touchstart', touchstart, listenerOptions)
|
|
const touchmove = (e: TouchEvent) => {
|
|
if (e.touches.length !== 1) {
|
|
return
|
|
}
|
|
const touch = e.touches[0]
|
|
const currentPoint = {
|
|
x: touch.clientX,
|
|
y: touch.clientY,
|
|
}
|
|
// if (!scroll) {
|
|
if (isValidMove(startPoint, currentPoint, minMoveDistance)) {
|
|
;(e.target as HTMLElement).dispatchEvent(composeMouseEvent('mousemove', touch))
|
|
move = true
|
|
if (e.cancelable) {
|
|
e.preventDefault()
|
|
}
|
|
} else {
|
|
move = false
|
|
}
|
|
// } else {
|
|
// const lastPoint = {
|
|
// x: lastTouch ? lastTouch.clientX : startPoint.x,
|
|
// y: lastTouch ? lastTouch.clientY : startPoint.y,
|
|
// }
|
|
// console.log('touch scroll', lastPoint, currentPoint);
|
|
// (e.target as HTMLElement).dispatchEvent(
|
|
// composeWheelEvent(lastPoint, currentPoint, startTouch)
|
|
// )
|
|
// }
|
|
lastTouch = touch
|
|
}
|
|
element.addEventListener('touchmove', touchmove, listenerOptions)
|
|
const touchend = (e: TouchEvent) => {
|
|
if (move) {
|
|
;(e.target as HTMLElement).dispatchEvent(composeMouseEvent('mouseup', lastTouch))
|
|
if (e.cancelable) {
|
|
e.preventDefault()
|
|
}
|
|
move = false
|
|
}
|
|
}
|
|
element.addEventListener('touchend', touchend, listenerOptions)
|
|
element.addEventListener('touchcancel', touchend, listenerOptions)
|
|
attachedHandlers.push({
|
|
element,
|
|
touchstart,
|
|
touchmove,
|
|
touchend,
|
|
})
|
|
}
|
|
/**
|
|
* 取消由`enableTouchMove`建立的触摸事件
|
|
* @param element 目标元素
|
|
*/
|
|
export const disableTouchMove = (element: HTMLElement) => {
|
|
const handlersIndex = attachedHandlers.findIndex(h => h.element === element)
|
|
if (handlersIndex === -1) {
|
|
return
|
|
}
|
|
const handlers = attachedHandlers[handlersIndex]
|
|
;['touchstart', 'touchmove', 'touchend'].forEach(event => {
|
|
element.removeEventListener(event, handlers[event], listenerOptions)
|
|
})
|
|
element.removeEventListener('touchcancel', handlers.touchend, listenerOptions)
|
|
attachedHandlers.splice(handlersIndex, 1)
|
|
}
|