64 lines
1.8 KiB
TypeScript
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)
|
|
}
|
|
})
|
|
};
|