vexip-ui
Version:
A Vue 3 UI library, Highly customizability, full TypeScript, performance pretty good
1 lines • 11.2 kB
Source Map (JSON)
{"version":3,"file":"hooks.cjs","sources":["../../../components/scroll/hooks.ts"],"sourcesContent":["import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'\n\nimport { useManualRef } from '@vexip-ui/hooks'\nimport { multipleFixed, toNumber } from '@vexip-ui/utils'\n\nimport type { Ref } from 'vue'\nimport type { ScrollMode } from './symbol'\n\nexport function useScrollWrapper({\n mode,\n disabled,\n width,\n height,\n scrollX,\n scrollY,\n onResize,\n onBeforeRefresh,\n onAfterRefresh,\n}: {\n mode: Ref<Exclude<ScrollMode, 'horizontal-exact'>>,\n disabled: Ref<boolean>,\n width: Ref<number | string>,\n height: Ref<number | string>,\n scrollX: Ref<number>,\n scrollY: Ref<number>,\n onResize?: (entry: ResizeObserverEntry) => void,\n onBeforeRefresh?: () => void,\n onAfterRefresh?: () => void,\n}) {\n const { manualRef, triggerUpdate } = useManualRef()\n\n const wrapperEl = ref<HTMLElement>()\n const contentEl = ref<HTMLElement>()\n\n // 容器长宽\n const wrapper = reactive({\n el: wrapperEl,\n width: toNumber(width.value),\n height: toNumber(height.value),\n })\n\n // 内容长宽\n const content = reactive({\n el: contentEl,\n width: 0,\n height: 0,\n })\n\n const x = manualRef(-scrollX.value)\n const y = manualRef(-scrollY.value)\n\n const isReady = ref(false)\n\n const percentX = manualRef(0)\n const percentY = manualRef(0)\n\n const xScrollLimit = computed(() => {\n return wrapper.width ? wrapper.width - content.width : 0\n })\n const yScrollLimit = computed(() => {\n return wrapper.height ? wrapper.height - content.height : 0\n })\n const enableXScroll = computed(() => {\n return (\n !disabled.value &&\n mode.value !== 'vertical' &&\n !!wrapper.width &&\n content.width - wrapper.width > 1\n )\n })\n const enableYScroll = computed(() => {\n return (\n !disabled.value &&\n mode.value !== 'horizontal' &&\n !!wrapper.height &&\n content.height - wrapper.height > 1\n )\n })\n const xBarLength = computed(() => {\n if (wrapper.width) {\n return Math.max(Math.min((wrapper.width / (content.width || 1)) * 100, 99), 5)\n }\n\n return 35\n })\n const yBarLength = computed(() => {\n if (wrapper.height) {\n return Math.max(Math.min((wrapper.height / (content.height || 1)) * 100, 99), 5)\n }\n\n return 35\n })\n\n watch(wrapperEl, () => {\n refreshWrapper()\n })\n watch(contentEl, () => {\n computeContentSize()\n })\n watch(scrollX, value => {\n x.value = -value\n verifyScroll()\n })\n watch(scrollY, value => {\n y.value = -value\n verifyScroll()\n })\n watch(width, () => {\n refreshWrapper().then(verifyScroll)\n })\n watch(height, () => {\n refreshWrapper().then(verifyScroll)\n })\n\n function computeWrapperSize(sizeType: 'width' | 'height') {\n return nextTick(() => {\n if (!wrapper.el) return\n\n const size = sizeType === 'width' ? width.value : height.value\n const titleCaseSizeType = sizeType.slice(0, 1).toUpperCase() + sizeType.slice(1)\n\n // 获取 wrapper 的 px 大小\n if (typeof size === 'string') {\n if (!size.endsWith('px') && (!size || Number.isNaN(Number(size)))) {\n wrapper[sizeType] =\n wrapper.el[`offset${titleCaseSizeType}` as 'offsetWidth' | 'offsetHeight']\n } else {\n wrapper[sizeType] = parseInt(size)\n }\n } else {\n wrapper[sizeType] = size\n }\n })\n }\n\n async function refreshWrapper() {\n const promises: Promise<void>[] = []\n\n if (mode.value !== 'vertical') {\n promises.push(computeWrapperSize('width'))\n }\n\n if (mode.value !== 'horizontal') {\n promises.push(computeWrapperSize('height'))\n }\n\n await Promise.all(promises)\n }\n\n let timer: ReturnType<typeof setTimeout>\n\n function computeContentSize() {\n clearTimeout(timer)\n\n return new Promise<void>(resolve => {\n isReady.value = false\n\n timer = setTimeout(() => {\n if (!content.el) {\n resolve()\n return\n }\n\n if (mode.value !== 'vertical') {\n content.width = content.el.offsetWidth\n\n if (wrapper.width >= content.width) {\n x.value = 0\n } else {\n if (x.value === 0) {\n x.value = -scrollX.value\n }\n }\n }\n\n if (mode.value !== 'horizontal') {\n content.height = content.el.offsetHeight\n\n if (wrapper.height >= content.height) {\n y.value = 0\n } else {\n if (y.value === 0) {\n y.value = -scrollY.value\n }\n }\n }\n\n setTimeout(() => {\n isReady.value = true\n verifyScroll()\n resolve()\n }, 1)\n }, 0)\n })\n }\n\n /**\n * Will post process the percent scroll values.\n */\n function verifyScroll() {\n if (!isReady.value) {\n return\n }\n\n if (mode.value !== 'vertical') {\n x.value = Math.min(0, Math.max(x.value, xScrollLimit.value))\n\n if (mode.value !== 'both') {\n y.value = 0\n }\n }\n\n if (mode.value !== 'horizontal') {\n y.value = Math.min(0, Math.max(y.value, yScrollLimit.value))\n\n if (mode.value !== 'both') {\n x.value = 0\n }\n }\n\n computePercent()\n triggerUpdate()\n }\n\n function computePercent() {\n percentX.value = multipleFixed(x.value / (xScrollLimit.value || -1), 100, 2)\n percentY.value = multipleFixed(y.value / (yScrollLimit.value || -1), 100, 2)\n\n percentX.value = Math.max(0, Math.min(percentX.value, 100))\n percentY.value = Math.max(0, Math.min(percentY.value, 100))\n }\n\n function handleResize(entity: ResizeObserverEntry) {\n refresh()\n onResize?.(entity)\n }\n\n let isMounted = false\n\n onMounted(() => {\n refresh()\n isMounted = true\n })\n\n async function refresh() {\n if (typeof onBeforeRefresh === 'function') {\n onBeforeRefresh()\n }\n\n refreshWrapper()\n await computeContentSize().then(() => {\n setTimeout(\n () => {\n verifyScroll()\n\n if (typeof onAfterRefresh === 'function') {\n onAfterRefresh()\n }\n },\n isMounted ? 20 : 100,\n )\n })\n }\n\n return {\n wrapperEl,\n contentEl,\n\n wrapper,\n content,\n isReady,\n x,\n y,\n percentX,\n percentY,\n xScrollLimit,\n yScrollLimit,\n enableXScroll,\n enableYScroll,\n xBarLength,\n yBarLength,\n\n handleResize,\n verifyScroll,\n computePercent,\n refresh,\n triggerUpdate,\n }\n}\n"],"names":["useScrollWrapper","mode","disabled","width","height","scrollX","scrollY","onResize","onBeforeRefresh","onAfterRefresh","manualRef","triggerUpdate","useManualRef","wrapperEl","ref","contentEl","wrapper","reactive","toNumber","content","x","y","isReady","percentX","percentY","xScrollLimit","computed","yScrollLimit","enableXScroll","enableYScroll","xBarLength","yBarLength","watch","refreshWrapper","computeContentSize","value","verifyScroll","computeWrapperSize","sizeType","nextTick","size","titleCaseSizeType","promises","timer","resolve","computePercent","multipleFixed","handleResize","entity","refresh","isMounted","onMounted"],"mappings":"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"}