vexip-ui
Version:
A Vue 3 UI library, Highly customizability, full TypeScript, performance pretty good
1 lines • 10.5 kB
Source Map (JSON)
{"version":3,"file":"affix.vue2.cjs","sources":["../../../components/affix/affix.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n computed,\n getCurrentInstance,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n watch,\n watchEffect,\n} from 'vue'\n\nimport { emitEvent, useNameHelper, useProps } from '@vexip-ui/config'\nimport { affixProps } from './props'\nimport { callIfFunc, isClient, isElement } from '@vexip-ui/utils'\nimport { clearLastScroller, handleLastScroller } from './helpers'\n\nimport type { NativeScrollExposed } from '@/components/native-scroll'\nimport type { ScrollExposed } from '@/components/scroll'\n\nimport type { CSSProperties, ComponentInternalInstance } from 'vue'\n\ntype ScrollType = NativeScrollExposed & ScrollExposed\n\ndefineOptions({ name: 'Affix' })\n\nconst _props = defineProps(affixProps)\nconst props = useProps('affix', _props, {\n offset: 0,\n zIndex: 100,\n position: 'top',\n target: null,\n})\n\nconst nh = useNameHelper('affix')\n\nconst instance = getCurrentInstance()!\n\nconst wrapper = shallowRef<HTMLElement>()\nconst target = shallowRef<HTMLElement>()\nconst container = shallowRef<Window | HTMLElement>()\n\nlet isRawViewer = false\nlet scroller: ScrollType | null = null\n\nconst fixed = ref(false)\nconst affixHeight = ref(0)\nconst affixWidth = ref(0)\nconst scrollTop = ref(0)\nconst clientHeight = ref(0)\nconst transform = ref(0)\n\nconst affixStyle = computed<CSSProperties>(() => {\n return {\n height: fixed.value ? `${affixHeight.value}px` : '',\n width: fixed.value ? `${affixWidth.value}px` : '',\n }\n})\nconst fixedStyle = computed<CSSProperties>(() => {\n if (!fixed.value) return {}\n\n let _top = props.offset\n let _bottom = props.offset\n\n if (isElement(container.value)) {\n if (props.target && props.position === 'top') {\n _top += transform.value\n } else {\n _bottom += transform.value\n }\n }\n\n return {\n height: `${affixHeight.value}px`,\n width: `${affixWidth.value}px`,\n top: props.position === 'top' ? `${_top}px` : '',\n bottom: props.position === 'bottom' ? `${_bottom}px` : '',\n zIndex: props.zIndex,\n }\n})\n\nwatchEffect(update)\nwatch(fixed, fixed => {\n emitEvent(props.onChange, fixed)\n})\n\ndefineExpose({ update })\n\nonMounted(() => {\n if (props.target) {\n const _target: unknown = callIfFunc(props.target)\n\n if (typeof _target === 'string') {\n target.value = document.querySelector<HTMLElement>(_target) ?? undefined\n\n if (!target.value) {\n throw new Error(`[vexip-ui:Affix] target not exists: ${props.target}`)\n }\n } else {\n target.value = _target as any\n }\n } else {\n target.value = document.documentElement\n }\n\n updateContainer()\n})\n\nonBeforeUnmount(() => {\n removeListener()\n})\n\nfunction update() {\n if (!wrapper.value || !target.value || !container.value) return\n\n const wrapperRect = wrapper.value.getBoundingClientRect()\n const targetRect = target.value.getBoundingClientRect()\n\n affixHeight.value = wrapperRect.height\n affixWidth.value = wrapperRect.width\n scrollTop.value =\n container.value === window\n ? document.documentElement.scrollTop\n : (container.value as unknown as ScrollType).scrollY || 0\n scrollTop.value = document.documentElement.scrollTop\n clientHeight.value = document.documentElement.clientHeight\n\n if (props.position === 'top') {\n if (props.target) {\n transform.value = targetRect.top\n fixed.value = wrapperRect.top < targetRect.top + props.offset\n } else {\n fixed.value = props.offset > wrapperRect.top\n }\n } else {\n if (props.target) {\n transform.value = clientHeight.value - targetRect.bottom\n fixed.value = targetRect.bottom < props.offset + wrapperRect.bottom\n } else {\n fixed.value = clientHeight.value - props.offset < wrapperRect.bottom\n }\n }\n}\n\nfunction handleContainerScroll() {\n handleLastScroller(target)\n update()\n\n emitEvent(props.onScroll, {\n scrollTop: scrollTop.value,\n fixed: fixed.value,\n })\n}\n\nfunction updateContainer() {\n removeListener()\n\n if (!isClient) return\n\n if (props.target) {\n container.value = target.value!\n container.value.addEventListener('scroll', handleContainerScroll)\n } else {\n let _container: ComponentInternalInstance | null = instance.parent!\n const refName = 'scroll'\n\n while (_container) {\n const name = _container.type?.name\n\n if (name === 'Scroll' || name === 'NativeScroll') {\n const { exposeProxy, exposed, proxy } = _container\n const _scroller = new Proxy({} as any, {\n get(_, key) {\n return (proxy as any)?.[key] ?? (exposeProxy as any)?.[key] ?? (exposed as any)?.[key]\n },\n })\n const scrollerEl = _scroller?.$el as HTMLElement\n\n if (!scrollerEl.getAttribute('class')?.includes('vxp-native-scroll--horizontal')) {\n scroller = _scroller\n break\n }\n }\n\n const refTemp = _container.refs?.[refName]\n\n if (refTemp) {\n if (isElement(refTemp)) {\n isRawViewer = true\n container.value = refTemp as HTMLElement\n } else {\n scroller = refTemp as ScrollType\n }\n\n break\n }\n\n _container = _container.parent\n }\n\n if (scroller) {\n scroller.addScrollListener(handleContainerScroll)\n container.value = scroller.$el\n } else if (!container.value) {\n isRawViewer = true\n container.value = window\n }\n\n if (isRawViewer && container.value) {\n container.value.addEventListener('scroll', handleContainerScroll)\n }\n }\n}\n\nfunction removeListener() {\n if (scroller) {\n scroller.removeScrollListener(handleContainerScroll)\n scroller = null\n }\n\n if (container.value) {\n container.value.removeEventListener('scroll', handleContainerScroll)\n container.value = undefined\n }\n\n clearLastScroller(target)\n}\n</script>\n\n<template>\n <div ref=\"wrapper\" :class=\"nh.b()\" :style=\"affixStyle\">\n <div :class=\"{ [nh.bm('fixed')]: fixed }\" :style=\"fixedStyle\">\n <slot></slot>\n </div>\n </div>\n</template>\n"],"names":["_props","__props","props","useProps","nh","useNameHelper","instance","getCurrentInstance","wrapper","shallowRef","target","container","isRawViewer","scroller","fixed","ref","affixHeight","affixWidth","scrollTop","clientHeight","transform","affixStyle","computed","fixedStyle","_top","_bottom","isElement","watchEffect","update","watch","emitEvent","__expose","onMounted","_target","callIfFunc","updateContainer","onBeforeUnmount","removeListener","wrapperRect","targetRect","handleContainerScroll","handleLastScroller","isClient","_container","refName","name","_a","exposeProxy","exposed","proxy","_scroller","_","key","_b","refTemp","_c","clearLastScroller","_createElementBlock","_normalizeClass","_unref","_createElementVNode","_renderSlot","_ctx"],"mappings":"2OA0BA,MAAMA,EAASC,EACTC,EAAQC,EAAAA,SAAS,QAASH,EAAQ,CACtC,OAAQ,EACR,OAAQ,IACR,SAAU,MACV,OAAQ,IAAA,CACT,EAEKI,EAAKC,gBAAc,OAAO,EAE1BC,EAAWC,EAAAA,mBAAmB,EAE9BC,EAAUC,EAAAA,WAAwB,EAClCC,EAASD,EAAAA,WAAwB,EACjCE,EAAYF,EAAAA,WAAiC,EAEnD,IAAIG,EAAc,GACdC,EAA8B,KAE5B,MAAAC,EAAQC,MAAI,EAAK,EACjBC,EAAcD,MAAI,CAAC,EACnBE,EAAaF,MAAI,CAAC,EAClBG,EAAYH,MAAI,CAAC,EACjBI,EAAeJ,MAAI,CAAC,EACpBK,EAAYL,MAAI,CAAC,EAEjBM,EAAaC,EAAAA,SAAwB,KAClC,CACL,OAAQR,EAAM,MAAQ,GAAGE,EAAY,KAAK,KAAO,GACjD,MAAOF,EAAM,MAAQ,GAAGG,EAAW,KAAK,KAAO,EACjD,EACD,EACKM,EAAaD,EAAAA,SAAwB,IAAM,CAC/C,GAAI,CAACR,EAAM,MAAO,MAAO,CAAC,EAE1B,IAAIU,EAAOtB,EAAM,OACbuB,EAAUvB,EAAM,OAEhB,OAAAwB,EAAA,UAAUf,EAAU,KAAK,IACvBT,EAAM,QAAUA,EAAM,WAAa,MACrCsB,GAAQJ,EAAU,MAElBK,GAAWL,EAAU,OAIlB,CACL,OAAQ,GAAGJ,EAAY,KAAK,KAC5B,MAAO,GAAGC,EAAW,KAAK,KAC1B,IAAKf,EAAM,WAAa,MAAQ,GAAGsB,CAAI,KAAO,GAC9C,OAAQtB,EAAM,WAAa,SAAW,GAAGuB,CAAO,KAAO,GACvD,OAAQvB,EAAM,MAChB,CAAA,CACD,EAEDyB,EAAAA,YAAYC,CAAM,EACZC,QAAAf,EAAOA,GAAS,CACVgB,YAAA5B,EAAM,SAAUY,CAAK,CAAA,CAChC,EAEYiB,EAAA,CAAE,OAAAH,EAAQ,EAEvBI,EAAAA,UAAU,IAAM,CACd,GAAI9B,EAAM,OAAQ,CACV,MAAA+B,EAAmBC,EAAAA,WAAWhC,EAAM,MAAM,EAE5C,GAAA,OAAO+B,GAAY,UAGjB,GAFJvB,EAAO,MAAQ,SAAS,cAA2BuB,CAAO,GAAK,OAE3D,CAACvB,EAAO,MACV,MAAM,IAAI,MAAM,uCAAuCR,EAAM,MAAM,EAAE,OAGvEQ,EAAO,MAAQuB,CACjB,MAEAvB,EAAO,MAAQ,SAAS,gBAGVyB,EAAA,CAAA,CACjB,EAEDC,EAAAA,gBAAgB,IAAM,CACLC,EAAA,CAAA,CAChB,EAED,SAAST,GAAS,CACZ,GAAA,CAACpB,EAAQ,OAAS,CAACE,EAAO,OAAS,CAACC,EAAU,MAAO,OAEnD,MAAA2B,EAAc9B,EAAQ,MAAM,sBAAsB,EAClD+B,EAAa7B,EAAO,MAAM,sBAAsB,EAEtDM,EAAY,MAAQsB,EAAY,OAChCrB,EAAW,MAAQqB,EAAY,MACrBpB,EAAA,MACRP,EAAU,QAAU,OAChB,SAAS,gBAAgB,UACxBA,EAAU,MAAgC,SAAW,EAClDO,EAAA,MAAQ,SAAS,gBAAgB,UAC9BC,EAAA,MAAQ,SAAS,gBAAgB,aAE1CjB,EAAM,WAAa,MACjBA,EAAM,QACRkB,EAAU,MAAQmB,EAAW,IAC7BzB,EAAM,MAAQwB,EAAY,IAAMC,EAAW,IAAMrC,EAAM,QAEjDY,EAAA,MAAQZ,EAAM,OAASoC,EAAY,IAGvCpC,EAAM,QACEkB,EAAA,MAAQD,EAAa,MAAQoB,EAAW,OAClDzB,EAAM,MAAQyB,EAAW,OAASrC,EAAM,OAASoC,EAAY,QAE7DxB,EAAM,MAAQK,EAAa,MAAQjB,EAAM,OAASoC,EAAY,MAElE,CAGF,SAASE,GAAwB,CAC/BC,EAAAA,mBAAmB/B,CAAM,EAClBkB,EAAA,EAEPE,EAAA,UAAU5B,EAAM,SAAU,CACxB,UAAWgB,EAAU,MACrB,MAAOJ,EAAM,KAAA,CACd,CAAA,CAGH,SAASqB,GAAkB,WAGzB,GAFeE,EAAA,EAEX,EAACK,EAAAA,SAEL,GAAIxC,EAAM,OACRS,EAAU,MAAQD,EAAO,MACfC,EAAA,MAAM,iBAAiB,SAAU6B,CAAqB,MAC3D,CACL,IAAIG,EAA+CrC,EAAS,OAC5D,MAAMsC,EAAU,SAEhB,KAAOD,GAAY,CACX,MAAAE,GAAOC,EAAAH,EAAW,OAAX,YAAAG,EAAiB,KAE1B,GAAAD,IAAS,UAAYA,IAAS,eAAgB,CAChD,KAAM,CAAE,YAAAE,EAAa,QAAAC,EAAS,MAAAC,CAAU,EAAAN,EAClCO,EAAY,IAAI,MAAM,GAAW,CACrC,IAAIC,EAAGC,EAAK,CACV,OAAQH,GAAA,YAAAA,EAAgBG,MAASL,GAAA,YAAAA,EAAsBK,MAASJ,GAAA,YAAAA,EAAkBI,GAAG,CACvF,CACD,EAGD,GAAI,GAACC,GAFcH,GAAA,YAAAA,EAAW,KAEd,aAAa,OAAO,IAA/B,MAAAG,EAAkC,SAAS,kCAAkC,CACrExC,EAAAqC,EACX,KAAA,CACF,CAGI,MAAAI,GAAUC,EAAAZ,EAAW,OAAX,YAAAY,EAAkBX,GAElC,GAAIU,EAAS,CACP5B,EAAAA,UAAU4B,CAAO,GACL1C,EAAA,GACdD,EAAU,MAAQ2C,GAEPzC,EAAAyC,EAGb,KAAA,CAGFX,EAAaA,EAAW,MAAA,CAGtB9B,GACFA,EAAS,kBAAkB2B,CAAqB,EAChD7B,EAAU,MAAQE,EAAS,KACjBF,EAAU,QACNC,EAAA,GACdD,EAAU,MAAQ,QAGhBC,GAAeD,EAAU,OACjBA,EAAA,MAAM,iBAAiB,SAAU6B,CAAqB,CAClE,CACF,CAGF,SAASH,GAAiB,CACpBxB,IACFA,EAAS,qBAAqB2B,CAAqB,EACxC3B,EAAA,MAGTF,EAAU,QACFA,EAAA,MAAM,oBAAoB,SAAU6B,CAAqB,EACnE7B,EAAU,MAAQ,QAGpB6C,EAAAA,kBAAkB9C,CAAM,CAAA,6BAKxB+C,EAAA,mBAIM,MAAA,SAJG,UAAJ,IAAIjD,EAAW,MAAKkD,EAAAA,eAAEC,EAAAA,MAAEvD,CAAA,EAAC,GAAC,EAAK,uBAAOiB,EAAU,KAAA,CAAA,GACnDuC,EAAAA,mBAEM,MAAA,CAFA,MAAUF,EAAA,eAAA,CAAA,CAAAC,EAAAA,MAAAvD,CAAA,EAAG,aAAcU,EAAK,MAAA,EAAK,uBAAOS,EAAU,KAAA,CAAA,GAC1DsC,aAAaC,EAAA,OAAA,SAAA,CAAA"}