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