@@ -8,15 +8,31 @@ const easeInOutQuad = (t: number, b: number, c: number, d: number): number => {
type Noop = ( ) = > void
const noop : Noop = ( ) = > { }
type ScrollElement < T > = {
lx_scrollLockKey? : number
lx_scrollNextParams ? : [ ScrollElement < HTMLElement > , number , number , Noop ]
lx_scrollTimeout? : number
lx_scrollDelayTimeout? : number
} & T
const handleScrollY = ( element : HTMLElement , to : number , duration = 300 , fn = noop ) : Noop = > {
const handleScrollY = ( element : ScrollElement < HTMLElement > , to : number , duration = 300 , fn = noop ) : Noop = > {
if ( ! element ) {
fn ( )
return noop
}
const clean = ( ) = > {
element . lx_scrollLockKey = undefined
element . lx_scrollNextParams = undefined
if ( element . lx_scrollTimeout ) window . clearTimeout ( element . lx_scrollTimeout )
element . lx_scrollTimeout = undefined
}
if ( element . lx_scrollLockKey ) {
element . lx_scrollNextParams = [ element , to , duration , fn ]
element . lx_scrollLockKey = - 1
return clean
}
// @ts-expect-error
const start = element . scrollTop ? ? element . scrollY ? ? 0
let cancel = false
if ( to > start ) {
let maxScrollTop = element . scrollHeight - element . clientHeight
if ( to > maxScrollTop ) to = maxScrollTop
@@ -34,9 +50,19 @@ const handleScrollY = (element: HTMLElement, to: number, duration = 300, fn = no
}
let currentTime = 0
let val
let val : number
let key = Math . random ( )
const animateScroll = ( ) = > {
element . lx_scrollTimeout = undefined
// if (element.lx_scrollLockKey != key) {
if ( element . lx_scrollNextParams && currentTime > duration * 0.75 ) {
const [ _element , to , duration , fn ] = element . lx_scrollNextParams
clean ( )
handleScrollY ( _element , to , duration , fn )
return
}
currentTime += increment
val = Math . trunc ( easeInOutQuad ( currentTime , start , change , duration ) )
if ( element . scrollTo ) {
@@ -45,19 +71,23 @@ const handleScrollY = (element: HTMLElement, to: number, duration = 300, fn = no
element . scrollTop = val
}
if ( currentTime < duration ) {
if ( cancel ) {
fn ( )
return
}
window . setTimeout ( animateScroll , increment )
element . lx_scrollTimeout = window . setTimeout ( animateScroll , increment )
} else {
if ( element . lx_scrollNextParams ) {
const [ _element , to , duration , fn ] = element . lx_scrollNextParams
clean ( )
handleScrollY ( _element , to , duration , fn )
} else {
clean ( )
fn ( )
}
}
animateScroll ( )
return ( ) = > {
cancel = true
}
element . lx_scrollLockKey = key
animateScroll ( )
return clean
}
/**
* 设置滚动条位置
@@ -67,16 +97,24 @@ const handleScrollY = (element: HTMLElement, to: number, duration = 300, fn = no
* @param {*} fn 滚动完成后的回调
* @param {*} delay 延迟执行时间
*/
export const scrollTo = ( element : HTMLElement , to : number , duration = 300 , fn = ( ) = > { } , delay = 0 ) : ( ) = > void = > {
export const scrollTo = ( element : ScrollElement < HTMLElement > , to : number , duration = 300 , fn = ( ) = > { } , delay = 0 ) : ( ) = > void = > {
let cancelFn : ( ) = > void
let timeout : number | null
if ( element . lx_scrollDelayTimeout != null ) {
window . clearTimeout ( element . lx_scrollDelayTimeout )
element . lx_scrollDelayTimeout = undefined
}
if ( delay ) {
let scrollCancelFn : Noop
cancelFn = ( ) = > {
timeout == null ? scrollCancelFn ? . ( ) : clearTimeout ( timeout )
if ( element . lx_scrollDelayTimeout == null ) {
scrollCancelFn ? . ( )
} else {
window . clearTimeout ( element . lx_scrollDelayTimeout )
element . lx_scrollDelayTimeout = undefined
}
timeout = window . setTimeout ( ( ) = > {
timeout = null
}
element . lx_scrollDelayTimeout = window . setTimeout ( ( ) = > {
element . lx_scrollDelayTimeout = undefined
scrollCancelFn = handleScrollY ( element , to , duration , fn )
} , delay )
} else {
@@ -84,14 +122,24 @@ export const scrollTo = (element: HTMLElement, to: number, duration = 300, fn =
}
return cancelFn
}
const handleScrollX = ( element : HTMLElement , to : number , duration = 300 , fn = ( ) = > { } ) : ( ) = > void = > {
const handleScrollX = ( element : ScrollElement < HTMLElement > , to : number , duration = 300 , fn = ( ) = > { } ) : ( ) = > void = > {
if ( ! element ) {
fn ( )
return noop
}
const clean = ( ) = > {
element . lx_scrollLockKey = undefined
element . lx_scrollNextParams = undefined
if ( element . lx_scrollTimeout ) window . clearTimeout ( element . lx_scrollTimeout )
element . lx_scrollTimeout = undefined
}
if ( element . lx_scrollLockKey ) {
element . lx_scrollNextParams = [ element , to , duration , fn ]
element . lx_scrollLockKey = - 1
return clean
}
// @ts-expect-error
const start = element . scrollLeft || element . scrollX || 0
let cancel = false
if ( to > start ) {
let maxScrollLeft = element . scrollWidth - element . clientWidth
if ( to > maxScrollLeft ) to = maxScrollLeft
@@ -109,9 +157,18 @@ const handleScrollX = (element: HTMLElement, to: number, duration = 300, fn = ()
}
let currentTime = 0
let val
let val : number
let key = Math . random ( )
const animateScroll = ( ) = > {
element . lx_scrollTimeout = undefined
if ( element . lx_scrollNextParams && currentTime > duration * 0.75 ) {
const [ _element , to , duration , fn ] = element . lx_scrollNextParams
clean ( )
handleScrollY ( _element , to , duration , fn )
return
}
currentTime += increment
val = Math . trunc ( easeInOutQuad ( currentTime , start , change , duration ) )
if ( element . scrollTo ) {
@@ -120,19 +177,21 @@ const handleScrollX = (element: HTMLElement, to: number, duration = 300, fn = ()
element . scrollLeft = val
}
if ( currentTime < duration ) {
if ( cancel ) {
fn ( )
return
}
window . setTimeout ( animateScroll , increment )
element . lx_scrollTimeout = window . setTimeout ( animateScroll , increment )
} else {
if ( element . lx_scrollNextParams ) {
const [ _element , to , duration , fn ] = element . lx_scrollNextParams
clean ( )
handleScrollY ( _element , to , duration , fn )
} else {
clean ( )
fn ( )
}
}
animateScroll ( )
return ( ) = > {
cancel = true
}
element . lx_scrollLockKey = key
animateScroll ( )
return clean
}
/**
* 设置滚动条位置
@@ -142,16 +201,24 @@ const handleScrollX = (element: HTMLElement, to: number, duration = 300, fn = ()
* @param {*} fn 滚动完成后的回调
* @param {*} delay 延迟执行时间
*/
export const scrollXTo = ( element : HTMLElement , to : number , duration = 300 , fn = ( ) = > { } , delay = 0 ) : ( ) = > void = > {
export const scrollXTo = ( element : ScrollElement < HTMLElement > , to : number , duration = 300 , fn = ( ) = > { } , delay = 0 ) : ( ) = > void = > {
let cancelFn : Noop
let timeout : number | null
if ( element . lx_scrollDelayTimeout != null ) {
window . clearTimeout ( element . lx_scrollDelayTimeout )
element . lx_scrollDelayTimeout = undefined
}
if ( delay ) {
let scrollCancelFn : Noop
cancelFn = ( ) = > {
timeout == null ? scrollCancelFn ? . ( ) : clearTimeout ( timeout )
if ( element . lx_scrollDelayTimeout == null ) {
scrollCancelFn ? . ( )
} else {
window . clearTimeout ( element . lx_scrollDelayTimeout )
element . lx_scrollDelayTimeout = undefined
}
timeout = window . setTimeout ( ( ) = > {
timeout = null
}
element . lx_scrollDelayTimeout = window . setTimeout ( ( ) = > {
element . lx_scrollDelayTimeout = undefined
scrollCancelFn = handleScrollX ( element , to , duration , fn )
} , delay )
} else {
@@ -160,14 +227,24 @@ export const scrollXTo = (element: HTMLElement, to: number, duration = 300, fn =
return cancelFn
}
const handleScrollXR = ( element : HTMLElement , to : number , duration = 300 , fn = ( ) = > { } ) : ( ) = > void = > {
const handleScrollXR = ( element : ScrollElement < HTMLElement > , to : number , duration = 300 , fn = ( ) = > { } ) : ( ) = > void = > {
if ( ! element ) {
fn ( )
return noop
}
const clean = ( ) = > {
element . lx_scrollLockKey = undefined
element . lx_scrollNextParams = undefined
if ( element . lx_scrollTimeout ) window . clearTimeout ( element . lx_scrollTimeout )
element . lx_scrollTimeout = undefined
}
if ( element . lx_scrollLockKey ) {
element . lx_scrollNextParams = [ element , to , duration , fn ]
element . lx_scrollLockKey = - 1
return clean
}
// @ts-expect-error
const start = element . scrollLeft || element . scrollX as number || 0
let cancel = false
if ( to < start ) {
let maxScrollLeft = - element . scrollWidth + element . clientWidth
if ( to < maxScrollLeft ) to = maxScrollLeft
@@ -186,9 +263,18 @@ const handleScrollXR = (element: HTMLElement, to: number, duration = 300, fn = (
}
let currentTime = 0
let val
let val : number
let key = Math . random ( )
const animateScroll = ( ) = > {
element . lx_scrollTimeout = undefined
if ( element . lx_scrollNextParams && currentTime > duration * 0.75 ) {
const [ _element , to , duration , fn ] = element . lx_scrollNextParams
clean ( )
handleScrollY ( _element , to , duration , fn )
return
}
currentTime += increment
val = Math . trunc ( easeInOutQuad ( currentTime , start , change , duration ) )
@@ -198,19 +284,23 @@ const handleScrollXR = (element: HTMLElement, to: number, duration = 300, fn = (
element . scrollLeft = val
}
if ( currentTime < duration ) {
if ( cancel ) {
fn ( )
return
}
window . setTimeout ( animateScroll , increment )
element . lx_scrollTimeout = window . setTimeout ( animateScroll , increment )
} else {
if ( element . lx_scrollNextParams ) {
const [ _element , to , duration , fn ] = element . lx_scrollNextParams
clean ( )
handleScrollY ( _element , to , duration , fn )
} else {
clean ( )
fn ( )
}
}
animateScroll ( )
return ( ) = > {
cancel = true
}
element . lx_scrollLockKey = key
animateScroll ( )
return clean
}
/**
* 设置滚动条位置 ( writing-mode: vertical-rl 专用)
@@ -220,16 +310,24 @@ const handleScrollXR = (element: HTMLElement, to: number, duration = 300, fn = (
* @param fn 滚动完成后的回调
* @param delay 延迟执行时间
*/
export const scrollXRTo = ( element : HTMLElement , to : number , duration = 300 , fn = ( ) = > { } , delay = 0 ) : ( ) = > void = > {
export const scrollXRTo = ( element : ScrollElement < HTMLElement > , to : number , duration = 300 , fn = ( ) = > { } , delay = 0 ) : ( ) = > void = > {
let cancelFn : Noop
let timeout : number | null
if ( element . lx_scrollDelayTimeout != null ) {
window . clearTimeout ( element . lx_scrollDelayTimeout )
element . lx_scrollDelayTimeout = undefined
}
if ( delay ) {
let scrollCancelFn : Noop
cancelFn = ( ) = > {
timeout == null ? scrollCancelFn ? . ( ) : clearTimeout ( timeout )
if ( element . lx_scrollDelayTimeout == null ) {
scrollCancelFn ? . ( )
} else {
window . clearTimeout ( element . lx_scrollDelayTimeout )
element . lx_scrollDelayTimeout = undefined
}
timeout = window . setTimeout ( ( ) = > {
timeout = null
}
element . lx_scrollDelayTimeout = window . setTimeout ( ( ) = > {
element . lx_scrollDelayTimeout = undefined
scrollCancelFn = handleScrollXR ( element , to , duration , fn )
} , delay )
} else {