提交 | 用户 | age
|
a1d956
|
1 |
import type { FunctionArgs } from '@vueuse/core'; |
2f6253
|
2 |
import { upperFirst } from 'lodash-es'; |
陈 |
3 |
|
|
4 |
export interface ViewportOffsetResult { |
|
5 |
left: number; |
|
6 |
top: number; |
|
7 |
right: number; |
|
8 |
bottom: number; |
|
9 |
rightIncludeBody: number; |
|
10 |
bottomIncludeBody: number; |
|
11 |
} |
|
12 |
|
|
13 |
export function getBoundingClientRect(element: Element): DOMRect | number { |
|
14 |
if (!element || !element.getBoundingClientRect) { |
|
15 |
return 0; |
|
16 |
} |
|
17 |
return element.getBoundingClientRect(); |
|
18 |
} |
bdce84
|
19 |
|
8a9ca4
|
20 |
function trim(string: string) { |
2f6253
|
21 |
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, ''); |
8a9ca4
|
22 |
} |
bdce84
|
23 |
|
2f6253
|
24 |
/* istanbul ignore next */ |
陈 |
25 |
export function hasClass(el: Element, cls: string) { |
|
26 |
if (!el || !cls) return false; |
|
27 |
if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.'); |
|
28 |
if (el.classList) { |
|
29 |
return el.classList.contains(cls); |
|
30 |
} else { |
|
31 |
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1; |
|
32 |
} |
|
33 |
} |
bdce84
|
34 |
|
2f6253
|
35 |
/* istanbul ignore next */ |
陈 |
36 |
export function addClass(el: Element, cls: string) { |
|
37 |
if (!el) return; |
|
38 |
let curClass = el.className; |
|
39 |
const classes = (cls || '').split(' '); |
|
40 |
|
|
41 |
for (let i = 0, j = classes.length; i < j; i++) { |
|
42 |
const clsName = classes[i]; |
|
43 |
if (!clsName) continue; |
|
44 |
|
|
45 |
if (el.classList) { |
|
46 |
el.classList.add(clsName); |
|
47 |
} else if (!hasClass(el, clsName)) { |
|
48 |
curClass += ' ' + clsName; |
|
49 |
} |
|
50 |
} |
|
51 |
if (!el.classList) { |
|
52 |
el.className = curClass; |
|
53 |
} |
|
54 |
} |
|
55 |
|
|
56 |
/* istanbul ignore next */ |
|
57 |
export function removeClass(el: Element, cls: string) { |
|
58 |
if (!el || !cls) return; |
|
59 |
const classes = cls.split(' '); |
|
60 |
let curClass = ' ' + el.className + ' '; |
|
61 |
|
|
62 |
for (let i = 0, j = classes.length; i < j; i++) { |
|
63 |
const clsName = classes[i]; |
|
64 |
if (!clsName) continue; |
|
65 |
|
|
66 |
if (el.classList) { |
|
67 |
el.classList.remove(clsName); |
|
68 |
} else if (hasClass(el, clsName)) { |
|
69 |
curClass = curClass.replace(' ' + clsName + ' ', ' '); |
|
70 |
} |
|
71 |
} |
|
72 |
if (!el.classList) { |
|
73 |
el.className = trim(curClass); |
|
74 |
} |
|
75 |
} |
|
76 |
/** |
be3a3e
|
77 |
* Get the left and top offset of the current element |
V |
78 |
* left: the distance between the leftmost element and the left side of the document |
|
79 |
* top: the distance from the top of the element to the top of the document |
|
80 |
* right: the distance from the far right of the element to the right of the document |
|
81 |
* bottom: the distance from the bottom of the element to the bottom of the document |
|
82 |
* rightIncludeBody: the distance between the leftmost element and the right side of the document |
|
83 |
* bottomIncludeBody: the distance from the bottom of the element to the bottom of the document |
2f6253
|
84 |
* |
陈 |
85 |
* @description: |
|
86 |
*/ |
|
87 |
export function getViewportOffset(element: Element): ViewportOffsetResult { |
|
88 |
const doc = document.documentElement; |
|
89 |
|
|
90 |
const docScrollLeft = doc.scrollLeft; |
|
91 |
const docScrollTop = doc.scrollTop; |
|
92 |
const docClientLeft = doc.clientLeft; |
|
93 |
const docClientTop = doc.clientTop; |
|
94 |
|
|
95 |
const pageXOffset = window.pageXOffset; |
|
96 |
const pageYOffset = window.pageYOffset; |
|
97 |
|
|
98 |
const box = getBoundingClientRect(element); |
|
99 |
|
|
100 |
const { left: retLeft, top: rectTop, width: rectWidth, height: rectHeight } = box as DOMRect; |
|
101 |
|
|
102 |
const scrollLeft = (pageXOffset || docScrollLeft) - (docClientLeft || 0); |
|
103 |
const scrollTop = (pageYOffset || docScrollTop) - (docClientTop || 0); |
|
104 |
const offsetLeft = retLeft + pageXOffset; |
|
105 |
const offsetTop = rectTop + pageYOffset; |
|
106 |
|
|
107 |
const left = offsetLeft - scrollLeft; |
|
108 |
const top = offsetTop - scrollTop; |
|
109 |
|
|
110 |
const clientWidth = window.document.documentElement.clientWidth; |
|
111 |
const clientHeight = window.document.documentElement.clientHeight; |
|
112 |
return { |
|
113 |
left: left, |
|
114 |
top: top, |
|
115 |
right: clientWidth - rectWidth - left, |
|
116 |
bottom: clientHeight - rectHeight - top, |
|
117 |
rightIncludeBody: clientWidth - left, |
|
118 |
bottomIncludeBody: clientHeight - top, |
|
119 |
}; |
|
120 |
} |
|
121 |
|
|
122 |
export function hackCss(attr: string, value: string) { |
|
123 |
const prefix: string[] = ['webkit', 'Moz', 'ms', 'OT']; |
|
124 |
|
|
125 |
const styleObj: any = {}; |
|
126 |
prefix.forEach((item) => { |
|
127 |
styleObj[`${item}${upperFirst(attr)}`] = value; |
|
128 |
}); |
|
129 |
return { |
|
130 |
...styleObj, |
|
131 |
[attr]: value, |
|
132 |
}; |
|
133 |
} |
|
134 |
|
|
135 |
/* istanbul ignore next */ |
144ab5
|
136 |
export function on( |
bdce84
|
137 |
element: Element | HTMLElement | Document | Window, |
2f6253
|
138 |
event: string, |
56a966
|
139 |
handler: EventListenerOrEventListenerObject, |
2f6253
|
140 |
): void { |
陈 |
141 |
if (element && event && handler) { |
|
142 |
element.addEventListener(event, handler, false); |
|
143 |
} |
144ab5
|
144 |
} |
2f6253
|
145 |
|
陈 |
146 |
/* istanbul ignore next */ |
144ab5
|
147 |
export function off( |
bdce84
|
148 |
element: Element | HTMLElement | Document | Window, |
2f6253
|
149 |
event: string, |
56a966
|
150 |
handler: Fn, |
2f6253
|
151 |
): void { |
陈 |
152 |
if (element && event && handler) { |
|
153 |
element.removeEventListener(event, handler, false); |
|
154 |
} |
144ab5
|
155 |
} |
bdce84
|
156 |
|
V |
157 |
/* istanbul ignore next */ |
144ab5
|
158 |
export function once(el: HTMLElement, event: string, fn: EventListener): void { |
bdce84
|
159 |
const listener = function (this: any, ...args: unknown[]) { |
V |
160 |
if (fn) { |
|
161 |
fn.apply(this, args); |
|
162 |
} |
|
163 |
off(el, event, listener); |
|
164 |
}; |
|
165 |
on(el, event, listener); |
144ab5
|
166 |
} |
a1d956
|
167 |
|
Y |
168 |
export function useRafThrottle<T extends FunctionArgs>(fn: T): T { |
|
169 |
let locked = false; |
|
170 |
// @ts-ignore |
|
171 |
return function (...args: any[]) { |
|
172 |
if (locked) return; |
|
173 |
locked = true; |
|
174 |
window.requestAnimationFrame(() => { |
|
175 |
// @ts-ignore |
|
176 |
fn.apply(this, args); |
|
177 |
locked = false; |
|
178 |
}); |
|
179 |
}; |
|
180 |
} |