Files
Code-Create/src/directives/scroll-progress.ts
2026-05-15 16:41:52 +08:00

64 lines
1.8 KiB
TypeScript

/**
* 监听滚动条 滚动进度变化
* v-scroll-progress.self="(p) => console.log(p)"
* @modifiers self 监听当前元素的滚动进度变化
* @param params 滚动进度回调函数
* @param p 滚动进度
*/
const rootMap = new Map()
export default {
name: 'scroll-progress',
mounted(el: HTMLElement, binding: any) {
const params = binding.value
const { self } = binding.modifiers
const paramsType = typeof params
const obj = {
onscroll: () => { },
el,
root: self ? el : document,
activeNum: 0,
};
if (paramsType === 'function') {
obj.onscroll = params
} else if (paramsType === 'object') {
if (params.onscroll) obj.onscroll = params.onscroll
if (params.GetRoot) obj.root = params.GetRoot()
if (params.hasOwnProperty('activeNum')) obj.activeNum = params.activeNum
}
requestAnimationFrame(() => handleScroll({ target: obj.root }))
if (rootMap.has(obj.root)) {
rootMap.get(obj.root).push(obj)
return
}
rootMap.set(obj.root, [obj])
obj.root.addEventListener('scroll', handleScroll)
},
beforeUnmount(el: HTMLElement) {
rootMap.forEach((objs, root) => {
if (objs.some((v: any) => v.el === el)) {
objs = objs.filter((v_: any) => v_.el !== el)
rootMap.set(root, objs)
}
if (objs.length === 0) {
root.removeEventListener('scroll', handleScroll)
rootMap.delete(root)
}
})
},
};
function handleScroll(e: any) {
const target = e.target
const objs = rootMap.get(target)
if (!objs || objs.length === 0) return
const el = target === document ? document.documentElement : target as HTMLElement
const num = el.scrollTop / (el.scrollHeight - el.clientHeight);
const progress = Math.round(num * 100)
objs.forEach((obj: any) => {
obj?.onscroll(progress)
if (obj.el) {
let isActive = progress > obj.activeNum
obj.el.classList.toggle('active', isActive)
}
})
};