From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/utils/domUtils.ts | 289 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 289 insertions(+), 0 deletions(-)
diff --git a/src/utils/domUtils.ts b/src/utils/domUtils.ts
new file mode 100644
index 0000000..dbc1989
--- /dev/null
+++ b/src/utils/domUtils.ts
@@ -0,0 +1,289 @@
+import { isServer } from './is'
+const ieVersion = isServer ? 0 : Number((document as any).documentMode)
+const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g
+const MOZ_HACK_REGEXP = /^moz([A-Z])/
+
+export interface ViewportOffsetResult {
+ left: number
+ top: number
+ right: number
+ bottom: number
+ rightIncludeBody: number
+ bottomIncludeBody: number
+}
+
+/* istanbul ignore next */
+const trim = function (string: string) {
+ return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '')
+}
+
+/* istanbul ignore next */
+const camelCase = function (name: string) {
+ return name
+ .replace(SPECIAL_CHARS_REGEXP, function (_, __, letter, offset) {
+ return offset ? letter.toUpperCase() : letter
+ })
+ .replace(MOZ_HACK_REGEXP, 'Moz$1')
+}
+
+/* istanbul ignore next */
+export function hasClass(el: Element, cls: string) {
+ if (!el || !cls) return false
+ if (cls.indexOf(' ') !== -1) {
+ throw new Error('className should not contain space.')
+ }
+ if (el.classList) {
+ return el.classList.contains(cls)
+ } else {
+ return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1
+ }
+}
+
+/* istanbul ignore next */
+export function addClass(el: Element, cls: string) {
+ if (!el) return
+ let curClass = el.className
+ const classes = (cls || '').split(' ')
+
+ for (let i = 0, j = classes.length; i < j; i++) {
+ const clsName = classes[i]
+ if (!clsName) continue
+
+ if (el.classList) {
+ el.classList.add(clsName)
+ } else if (!hasClass(el, clsName)) {
+ curClass += ' ' + clsName
+ }
+ }
+ if (!el.classList) {
+ el.className = curClass
+ }
+}
+
+/* istanbul ignore next */
+export function removeClass(el: Element, cls: string) {
+ if (!el || !cls) return
+ const classes = cls.split(' ')
+ let curClass = ' ' + el.className + ' '
+
+ for (let i = 0, j = classes.length; i < j; i++) {
+ const clsName = classes[i]
+ if (!clsName) continue
+
+ if (el.classList) {
+ el.classList.remove(clsName)
+ } else if (hasClass(el, clsName)) {
+ curClass = curClass.replace(' ' + clsName + ' ', ' ')
+ }
+ }
+ if (!el.classList) {
+ el.className = trim(curClass)
+ }
+}
+
+export function getBoundingClientRect(element: Element): DOMRect | number {
+ if (!element || !element.getBoundingClientRect) {
+ return 0
+ }
+ return element.getBoundingClientRect()
+}
+
+/**
+ * 鑾峰彇褰撳墠鍏冪礌鐨刲eft銆乼op鍋忕Щ
+ * left锛氬厓绱犳渶宸︿晶璺濈鏂囨。宸︿晶鐨勮窛绂�
+ * top:鍏冪礌鏈�椤剁璺濈鏂囨。椤剁鐨勮窛绂�
+ * right:鍏冪礌鏈�鍙充晶璺濈鏂囨。鍙充晶鐨勮窛绂�
+ * bottom锛氬厓绱犳渶搴曠璺濈鏂囨。搴曠鐨勮窛绂�
+ * rightIncludeBody锛氬厓绱犳渶宸︿晶璺濈鏂囨。鍙充晶鐨勮窛绂�
+ * bottomIncludeBody锛氬厓绱犳渶搴曠璺濈鏂囨。鏈�搴曢儴鐨勮窛绂�
+ *
+ * @description:
+ */
+export function getViewportOffset(element: Element): ViewportOffsetResult {
+ const doc = document.documentElement
+
+ const docScrollLeft = doc.scrollLeft
+ const docScrollTop = doc.scrollTop
+ const docClientLeft = doc.clientLeft
+ const docClientTop = doc.clientTop
+
+ const pageXOffset = window.pageXOffset
+ const pageYOffset = window.pageYOffset
+
+ const box = getBoundingClientRect(element)
+
+ const { left: retLeft, top: rectTop, width: rectWidth, height: rectHeight } = box as DOMRect
+
+ const scrollLeft = (pageXOffset || docScrollLeft) - (docClientLeft || 0)
+ const scrollTop = (pageYOffset || docScrollTop) - (docClientTop || 0)
+ const offsetLeft = retLeft + pageXOffset
+ const offsetTop = rectTop + pageYOffset
+
+ const left = offsetLeft - scrollLeft
+ const top = offsetTop - scrollTop
+
+ const clientWidth = window.document.documentElement.clientWidth
+ const clientHeight = window.document.documentElement.clientHeight
+ return {
+ left: left,
+ top: top,
+ right: clientWidth - rectWidth - left,
+ bottom: clientHeight - rectHeight - top,
+ rightIncludeBody: clientWidth - left,
+ bottomIncludeBody: clientHeight - top
+ }
+}
+
+/* istanbul ignore next */
+export const on = function (
+ element: HTMLElement | Document | Window,
+ event: string,
+ handler: EventListenerOrEventListenerObject
+): void {
+ if (element && event && handler) {
+ element.addEventListener(event, handler, false)
+ }
+}
+
+/* istanbul ignore next */
+export const off = function (
+ element: HTMLElement | Document | Window,
+ event: string,
+ handler: any
+): void {
+ if (element && event && handler) {
+ element.removeEventListener(event, handler, false)
+ }
+}
+
+/* istanbul ignore next */
+export const once = function (el: HTMLElement, event: string, fn: EventListener): void {
+ const listener = function (this: any, ...args: unknown[]) {
+ if (fn) {
+ // @ts-ignore
+ fn.apply(this, args)
+ }
+ off(el, event, listener)
+ }
+ on(el, event, listener)
+}
+
+/* istanbul ignore next */
+export const getStyle =
+ ieVersion < 9
+ ? function (element: Element | any, styleName: string) {
+ if (isServer) return
+ if (!element || !styleName) return null
+ styleName = camelCase(styleName)
+ if (styleName === 'float') {
+ styleName = 'styleFloat'
+ }
+ try {
+ switch (styleName) {
+ case 'opacity':
+ try {
+ return element.filters.item('alpha').opacity / 100
+ } catch (e) {
+ return 1.0
+ }
+ default:
+ return element.style[styleName] || element.currentStyle
+ ? element.currentStyle[styleName]
+ : null
+ }
+ } catch (e) {
+ return element.style[styleName]
+ }
+ }
+ : function (element: Element | any, styleName: string) {
+ if (isServer) return
+ if (!element || !styleName) return null
+ styleName = camelCase(styleName)
+ if (styleName === 'float') {
+ styleName = 'cssFloat'
+ }
+ try {
+ const computed = (document as any).defaultView.getComputedStyle(element, '')
+ return element.style[styleName] || computed ? computed[styleName] : null
+ } catch (e) {
+ return element.style[styleName]
+ }
+ }
+
+/* istanbul ignore next */
+export function setStyle(element: Element | any, styleName: any, value: any) {
+ if (!element || !styleName) return
+
+ if (typeof styleName === 'object') {
+ for (const prop in styleName) {
+ if (Object.prototype.hasOwnProperty.call(styleName, prop)) {
+ setStyle(element, prop, styleName[prop])
+ }
+ }
+ } else {
+ styleName = camelCase(styleName)
+ if (styleName === 'opacity' && ieVersion < 9) {
+ element.style.filter = isNaN(value) ? '' : 'alpha(opacity=' + value * 100 + ')'
+ } else {
+ element.style[styleName] = value
+ }
+ }
+}
+
+/* istanbul ignore next */
+export const isScroll = (el: Element, vertical: any) => {
+ if (isServer) return
+
+ const determinedDirection = vertical !== null || vertical !== undefined
+ const overflow = determinedDirection
+ ? vertical
+ ? getStyle(el, 'overflow-y')
+ : getStyle(el, 'overflow-x')
+ : getStyle(el, 'overflow')
+
+ return overflow.match(/(scroll|auto)/)
+}
+
+/* istanbul ignore next */
+export const getScrollContainer = (el: Element, vertical?: any) => {
+ if (isServer) return
+
+ let parent: any = el
+ while (parent) {
+ if ([window, document, document.documentElement].includes(parent)) {
+ return window
+ }
+ if (isScroll(parent, vertical)) {
+ return parent
+ }
+ parent = parent.parentNode
+ }
+
+ return parent
+}
+
+/* istanbul ignore next */
+export const isInContainer = (el: Element, container: any) => {
+ if (isServer || !el || !container) return false
+
+ const elRect = el.getBoundingClientRect()
+ let containerRect
+
+ if ([window, document, document.documentElement, null, undefined].includes(container)) {
+ containerRect = {
+ top: 0,
+ right: window.innerWidth,
+ bottom: window.innerHeight,
+ left: 0
+ }
+ } else {
+ containerRect = container.getBoundingClientRect()
+ }
+
+ return (
+ elRect.top < containerRect.bottom &&
+ elRect.bottom > containerRect.top &&
+ elRect.right > containerRect.left &&
+ elRect.left < containerRect.right
+ )
+}
--
Gitblit v1.8.0