123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- import { isClient } from '@vueuse/core'
- import { getStyle } from './style'
- export const isScroll = (el: HTMLElement, isVertical?: boolean): boolean => {
- if (!isClient) return false
- const key = (
- {
- undefined: 'overflow',
- true: 'overflow-y',
- false: 'overflow-x',
- } as const
- )[String(isVertical)]!
- const overflow = getStyle(el, key)
- return ['scroll', 'auto', 'overlay'].some((s) => overflow.includes(s))
- }
- export const getScrollContainer = (
- el: HTMLElement,
- isVertical?: boolean
- ): Window | HTMLElement | undefined => {
- if (!isClient) return
- let parent: HTMLElement = el
- while (parent) {
- if ([window, document, document.documentElement].includes(parent))
- return window
- if (isScroll(parent, isVertical)) return parent
- parent = parent.parentNode as HTMLElement
- }
- return parent
- }
- let scrollBarWidth: number
- export const getScrollBarWidth = (namespace: string): number => {
- if (!isClient) return 0
- if (scrollBarWidth !== undefined) return scrollBarWidth
- const outer = document.createElement('div')
- outer.className = `${namespace}-scrollbar__wrap`
- outer.style.visibility = 'hidden'
- outer.style.width = '100px'
- outer.style.position = 'absolute'
- outer.style.top = '-9999px'
- document.body.appendChild(outer)
- const widthNoScroll = outer.offsetWidth
- outer.style.overflow = 'scroll'
- const inner = document.createElement('div')
- inner.style.width = '100%'
- outer.appendChild(inner)
- const widthWithScroll = inner.offsetWidth
- outer.parentNode?.removeChild(outer)
- scrollBarWidth = widthNoScroll - widthWithScroll
- return scrollBarWidth
- }
- /**
- * Scroll with in the container element, positioning the **selected** element at the top
- * of the container
- */
- export function scrollIntoView(
- container: HTMLElement,
- selected: HTMLElement
- ): void {
- if (!isClient) return
- if (!selected) {
- container.scrollTop = 0
- return
- }
- const offsetParents: HTMLElement[] = []
- let pointer = selected.offsetParent
- while (
- pointer !== null &&
- container !== pointer &&
- container.contains(pointer)
- ) {
- offsetParents.push(pointer as HTMLElement)
- pointer = (pointer as HTMLElement).offsetParent
- }
- const top =
- selected.offsetTop +
- offsetParents.reduce((prev, curr) => prev + curr.offsetTop, 0)
- const bottom = top + selected.offsetHeight
- const viewRectTop = container.scrollTop
- const viewRectBottom = viewRectTop + container.clientHeight
- if (top < viewRectTop) {
- container.scrollTop = top
- } else if (bottom > viewRectBottom) {
- container.scrollTop = bottom - container.clientHeight
- }
- }
|