From 335f30c887056387f7b9eee5eb4ab28540424253 Mon Sep 17 00:00:00 2001 From: vben <anncwb@126.com> Date: Fri, 7 Apr 2023 00:12:26 +0800 Subject: [PATCH] chore: 优化 useScrollTo、useWindowSizeFn --- packages/hooks/src/index.ts | 2 ++ packages/hooks/src/useAttrs.ts | 6 +++--- packages/hooks/src/useRefs.ts | 12 ++++++++++-- packages/hooks/src/useScrollTo.ts | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ packages/hooks/src/useWindowSizeFn.ts | 40 ++++++++++++++++++++++++++++++++++++++++ packages/types/src/utils.ts | 4 ++-- src/components/Application/src/search/AppSearchModal.vue | 2 +- src/components/Application/src/search/useMenuSearch.ts | 2 +- src/components/CodeEditor/src/codemirror/CodeMirror.vue | 14 ++++++++++++-- src/components/Container/src/ScrollContainer.vue | 3 ++- src/components/Modal/src/components/ModalWrapper.vue | 13 +++++++------ src/components/Table/src/hooks/useTableScroll.ts | 5 ++--- src/hooks/core/useContext.ts | 1 - src/hooks/event/useScrollTo.ts | 59 ----------------------------------------------------------- src/hooks/event/useWindowSizeFn.ts | 35 ----------------------------------- src/hooks/web/useContentHeight.ts | 6 ++---- src/hooks/web/useTitle.ts | 1 - src/layouts/default/content/useContentViewHeight.ts | 5 ++--- src/views/sys/iframe/index.vue | 4 ++-- 19 files changed, 148 insertions(+), 126 deletions(-) create mode 100644 packages/hooks/src/useScrollTo.ts create mode 100644 packages/hooks/src/useWindowSizeFn.ts delete mode 100644 src/hooks/event/useScrollTo.ts delete mode 100644 src/hooks/event/useWindowSizeFn.ts diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index e18d6d9..71fb0c5 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -1,4 +1,6 @@ export * from './onMountedOrActivated'; export * from './useAttrs'; export * from './useRefs'; +export * from './useScrollTo'; +export * from './useWindowSizeFn'; export { useTimeoutFn } from '@vueuse/core'; diff --git a/packages/hooks/src/useAttrs.ts b/packages/hooks/src/useAttrs.ts index c9b14ea..df2118d 100644 --- a/packages/hooks/src/useAttrs.ts +++ b/packages/hooks/src/useAttrs.ts @@ -1,7 +1,7 @@ import { type Recordable } from '@vben/types'; import { getCurrentInstance, reactive, shallowRef, watchEffect } from 'vue'; -interface Options { +interface UseAttrsOptions { excludeListeners?: boolean; excludeKeys?: string[]; excludeDefaultKeys?: boolean; @@ -14,7 +14,7 @@ function entries<T>(obj: Recordable<T>): [string, T][] { return Object.keys(obj).map((key: string) => [key, obj[key]]); } -function useAttrs(options: Options = {}): Recordable<any> { +function useAttrs(options: UseAttrsOptions = {}): Recordable<any> { const instance = getCurrentInstance(); if (!instance) return {}; @@ -40,4 +40,4 @@ function useAttrs(options: Options = {}): Recordable<any> { return attrs; } -export { useAttrs }; +export { useAttrs, type UseAttrsOptions }; diff --git a/packages/hooks/src/useRefs.ts b/packages/hooks/src/useRefs.ts index 4f3faf2..97f1b4b 100644 --- a/packages/hooks/src/useRefs.ts +++ b/packages/hooks/src/useRefs.ts @@ -1,7 +1,10 @@ import type { Ref } from 'vue'; import { onBeforeUpdate, shallowRef } from 'vue'; -export function useRefs(): [Ref<HTMLElement[]>, (index: number) => (el: HTMLElement) => void] { +function useRefs(): { + refs: Ref<HTMLElement[]>; + setRefs: (index: number) => (el: HTMLElement) => void; +} { const refs = shallowRef([]) as Ref<HTMLElement[]>; onBeforeUpdate(() => { @@ -12,5 +15,10 @@ export function useRefs(): [Ref<HTMLElement[]>, (index: number) => (el: HTMLElem refs.value[index] = el; }; - return [refs, setRefs]; + return { + refs, + setRefs, + }; } + +export { useRefs }; diff --git a/packages/hooks/src/useScrollTo.ts b/packages/hooks/src/useScrollTo.ts new file mode 100644 index 0000000..f6a95f4 --- /dev/null +++ b/packages/hooks/src/useScrollTo.ts @@ -0,0 +1,60 @@ +import { shallowRef, unref } from 'vue'; + +interface UseScrollToOptions { + el: any; + to: number; + duration?: number; + callback?: () => any; +} + +function easeInOutQuad(t: number, b: number, c: number, d: number) { + t /= d / 2; + if (t < 1) { + return (c / 2) * t * t + b; + } + t--; + return (-c / 2) * (t * (t - 2) - 1) + b; +} + +function move(el: HTMLElement, amount: number) { + el.scrollTop = amount; +} + +const position = (el: HTMLElement) => { + return el.scrollTop; +}; +function useScrollTo({ el, to, duration = 500, callback }: UseScrollToOptions) { + const isActiveRef = shallowRef(false); + const start = position(el); + const change = to - start; + const increment = 20; + let currentTime = 0; + + const animateScroll = function () { + if (!unref(isActiveRef)) { + return; + } + currentTime += increment; + const val = easeInOutQuad(currentTime, start, change, duration); + move(el, val); + if (currentTime < duration && unref(isActiveRef)) { + requestAnimationFrame(animateScroll); + } else { + if (callback && typeof callback === 'function') { + callback(); + } + } + }; + const run = () => { + isActiveRef.value = true; + animateScroll(); + }; + + const stop = () => { + isActiveRef.value = false; + }; + + return { start: run, stop }; +} + +export { useScrollTo, type UseScrollToOptions }; diff --git a/packages/hooks/src/useWindowSizeFn.ts b/packages/hooks/src/useWindowSizeFn.ts new file mode 100644 index 0000000..d8e7710 --- /dev/null +++ b/packages/hooks/src/useWindowSizeFn.ts @@ -0,0 +1,40 @@ +import { type AnyFunction } from '@vben/types'; +import { tryOnMounted, tryOnUnmounted, useDebounceFn } from '@vueuse/core'; + +interface UseWindowSizeOptions { + wait?: number; + once?: boolean; + immediate?: boolean; + listenerOptions?: AddEventListenerOptions | boolean; +} + +function useWindowSizeFn(fn: AnyFunction, options: UseWindowSizeOptions = {}) { + const { wait = 150, immediate } = options; + let handler = () => { + fn(); + }; + const handleSize = useDebounceFn(handler, wait); + handler = handleSize; + + const start = () => { + if (immediate) { + handler(); + } + window.addEventListener('resize', handler); + }; + + const stop = () => { + window.removeEventListener('resize', handler); + }; + + tryOnMounted(() => { + start(); + }); + + tryOnUnmounted(() => { + stop(); + }); + return { start, stop }; +} + +export { useWindowSizeFn, type UseWindowSizeOptions }; diff --git a/packages/types/src/utils.ts b/packages/types/src/utils.ts index 73e51f5..80435fc 100644 --- a/packages/types/src/utils.ts +++ b/packages/types/src/utils.ts @@ -1,12 +1,12 @@ /** * 任意类型的异步函数 */ -type AnyPromiseFunction = (...arg: any) => PromiseLike<any>; +type AnyPromiseFunction = (...arg: any[]) => PromiseLike<any>; /** * 任意类型的普通函数 */ -type AnyNormalFunction = (...arg: any) => any; +type AnyNormalFunction = (...arg: any[]) => any; /** * 任意类型的函数 diff --git a/src/components/Application/src/search/AppSearchModal.vue b/src/components/Application/src/search/AppSearchModal.vue index a1546f8..612b372 100644 --- a/src/components/Application/src/search/AppSearchModal.vue +++ b/src/components/Application/src/search/AppSearchModal.vue @@ -81,7 +81,7 @@ const { t } = useI18n(); const { prefixCls } = useDesign('app-search-modal'); - const [refs, setRefs] = useRefs(); + const { refs, setRefs } = useRefs(); const { getIsMobile } = useAppInject(); const { handleSearch, searchResult, keyword, activeIndex, handleEnter, handleMouseenter } = diff --git a/src/components/Application/src/search/useMenuSearch.ts b/src/components/Application/src/search/useMenuSearch.ts index 1b8c71f..c938792 100644 --- a/src/components/Application/src/search/useMenuSearch.ts +++ b/src/components/Application/src/search/useMenuSearch.ts @@ -5,7 +5,7 @@ import { getMenus } from '/@/router/menus'; import { cloneDeep } from 'lodash-es'; import { filter, forEach } from '/@/utils/helper/treeHelper'; import { useGo } from '/@/hooks/web/usePage'; -import { useScrollTo } from '/@/hooks/event/useScrollTo'; +import { useScrollTo } from '@vben/hooks'; import { onKeyStroke, useDebounceFn } from '@vueuse/core'; import { useI18n } from '/@/hooks/web/useI18n'; diff --git a/src/components/CodeEditor/src/codemirror/CodeMirror.vue b/src/components/CodeEditor/src/codemirror/CodeMirror.vue index 426ac36..af3017f 100644 --- a/src/components/CodeEditor/src/codemirror/CodeMirror.vue +++ b/src/components/CodeEditor/src/codemirror/CodeMirror.vue @@ -3,10 +3,20 @@ </template> <script lang="ts" setup> - import { ref, onMounted, onUnmounted, watchEffect, watch, unref, nextTick } from 'vue'; + import { + type PropType, + ref, + onMounted, + onUnmounted, + watchEffect, + watch, + unref, + nextTick, + } from 'vue'; + import type { Nullable } from '@vben/types'; + import { useWindowSizeFn } from '@vben/hooks'; import { useDebounceFn } from '@vueuse/core'; import { useAppStore } from '/@/store/modules/app'; - import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; import CodeMirror from 'codemirror'; import { MODE } from './../typing'; // css diff --git a/src/components/Container/src/ScrollContainer.vue b/src/components/Container/src/ScrollContainer.vue index 65c71ed..ca19003 100644 --- a/src/components/Container/src/ScrollContainer.vue +++ b/src/components/Container/src/ScrollContainer.vue @@ -7,7 +7,8 @@ <script lang="ts"> import { defineComponent, ref, unref, nextTick } from 'vue'; import { Scrollbar, ScrollbarType } from '/@/components/Scrollbar'; - import { useScrollTo } from '/@/hooks/event/useScrollTo'; + import { useScrollTo } from '@vben/hooks'; + import { type Nullable } from '@vben/types'; export default defineComponent({ name: 'ScrollContainer', diff --git a/src/components/Modal/src/components/ModalWrapper.vue b/src/components/Modal/src/components/ModalWrapper.vue index 699bf9c..037538c 100644 --- a/src/components/Modal/src/components/ModalWrapper.vue +++ b/src/components/Modal/src/components/ModalWrapper.vue @@ -18,7 +18,8 @@ nextTick, onUnmounted, } from 'vue'; - import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; + import { useWindowSizeFn } from '@vben/hooks'; + import { type AnyFunction } from '@vben/types'; import { ScrollContainer } from '/@/components/Container'; import { createModalContext } from '../hooks/useModalContext'; import { useMutationObserver } from '@vueuse/core'; @@ -43,14 +44,14 @@ props, emits: ['height-change', 'ext-height'], setup(props, { emit }) { - const wrapperRef = ref<ComponentRef>(null); - const spinRef = ref<ElRef>(null); + const wrapperRef = ref(null); + const spinRef = ref(null); const realHeightRef = ref(0); const minRealHeightRef = ref(0); let realHeight = 0; - let stopElResizeFn: Fn = () => {}; + let stopElResizeFn: AnyFunction = () => {}; useWindowSizeFn(setModalHeight.bind(null, false)); @@ -116,7 +117,7 @@ const wrapperRefDom = unref(wrapperRef); if (!wrapperRefDom) return; - const bodyDom = wrapperRefDom.$el.parentElement; + const bodyDom = (wrapperRefDom as any).$el.parentElement; if (!bodyDom) return; bodyDom.style.padding = '0'; await nextTick(); @@ -139,7 +140,7 @@ maxHeight -= 26; } await nextTick(); - const spinEl = unref(spinRef); + const spinEl: any = unref(spinRef); if (!spinEl) return; await nextTick(); diff --git a/src/components/Table/src/hooks/useTableScroll.ts b/src/components/Table/src/hooks/useTableScroll.ts index c4ecf1e..3777d6e 100644 --- a/src/components/Table/src/hooks/useTableScroll.ts +++ b/src/components/Table/src/hooks/useTableScroll.ts @@ -2,9 +2,8 @@ import type { BasicTableProps, TableRowSelection, BasicColumn } from '../types/t import { Ref, ComputedRef, ref, computed, unref, nextTick, watch } from 'vue'; import { getViewportOffset } from '/@/utils/domUtils'; import { isBoolean } from '/@/utils/is'; -import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; +import { useWindowSizeFn, onMountedOrActivated } from '@vben/hooks'; import { useModalContext } from '/@/components/Modal'; -import { onMountedOrActivated } from '@vben/hooks'; import { useDebounceFn } from '@vueuse/core'; export function useTableScroll( @@ -171,7 +170,7 @@ export function useTableScroll( bodyEl!.style.height = `${height}px`; } - useWindowSizeFn(calcTableHeight, 280); + useWindowSizeFn(calcTableHeight, { wait: 280 }); onMountedOrActivated(() => { calcTableHeight(); nextTick(() => { diff --git a/src/hooks/core/useContext.ts b/src/hooks/core/useContext.ts index c686187..2729526 100644 --- a/src/hooks/core/useContext.ts +++ b/src/hooks/core/useContext.ts @@ -4,7 +4,6 @@ import { inject, reactive, readonly as defineReadonly, - // defineComponent, UnwrapRef, } from 'vue'; diff --git a/src/hooks/event/useScrollTo.ts b/src/hooks/event/useScrollTo.ts deleted file mode 100644 index f6d5dc6..0000000 --- a/src/hooks/event/useScrollTo.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { isFunction, isUnDef } from '/@/utils/is'; -import { ref, unref } from 'vue'; - -export interface ScrollToParams { - el: any; - to: number; - duration?: number; - callback?: () => any; -} - -const easeInOutQuad = (t: number, b: number, c: number, d: number) => { - t /= d / 2; - if (t < 1) { - return (c / 2) * t * t + b; - } - t--; - return (-c / 2) * (t * (t - 2) - 1) + b; -}; -const move = (el: HTMLElement, amount: number) => { - el.scrollTop = amount; -}; - -const position = (el: HTMLElement) => { - return el.scrollTop; -}; -export function useScrollTo({ el, to, duration = 500, callback }: ScrollToParams) { - const isActiveRef = ref(false); - const start = position(el); - const change = to - start; - const increment = 20; - let currentTime = 0; - duration = isUnDef(duration) ? 500 : duration; - - const animateScroll = function () { - if (!unref(isActiveRef)) { - return; - } - currentTime += increment; - const val = easeInOutQuad(currentTime, start, change, duration); - move(el, val); - if (currentTime < duration && unref(isActiveRef)) { - requestAnimationFrame(animateScroll); - } else { - if (callback && isFunction(callback)) { - callback(); - } - } - }; - const run = () => { - isActiveRef.value = true; - animateScroll(); - }; - - const stop = () => { - isActiveRef.value = false; - }; - - return { start: run, stop }; -} diff --git a/src/hooks/event/useWindowSizeFn.ts b/src/hooks/event/useWindowSizeFn.ts deleted file mode 100644 index 01cdc75..0000000 --- a/src/hooks/event/useWindowSizeFn.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { tryOnMounted, tryOnUnmounted, useDebounceFn } from '@vueuse/core'; - -interface WindowSizeOptions { - once?: boolean; - immediate?: boolean; - listenerOptions?: AddEventListenerOptions | boolean; -} - -export function useWindowSizeFn<T>(fn: Fn<T>, wait = 150, options?: WindowSizeOptions) { - let handler = () => { - fn(); - }; - const handleSize = useDebounceFn(handler, wait); - handler = handleSize; - - const start = () => { - if (options && options.immediate) { - handler(); - } - window.addEventListener('resize', handler); - }; - - const stop = () => { - window.removeEventListener('resize', handler); - }; - - tryOnMounted(() => { - start(); - }); - - tryOnUnmounted(() => { - stop(); - }); - return [start, stop]; -} diff --git a/src/hooks/web/useContentHeight.ts b/src/hooks/web/useContentHeight.ts index 53fe0ef..558cd51 100644 --- a/src/hooks/web/useContentHeight.ts +++ b/src/hooks/web/useContentHeight.ts @@ -1,6 +1,5 @@ import { ComputedRef, isRef, nextTick, Ref, ref, unref, watch } from 'vue'; -import { onMountedOrActivated } from '@vben/hooks'; -import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; +import { onMountedOrActivated, useWindowSizeFn } from '@vben/hooks'; import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight'; import { getViewportOffset } from '/@/utils/domUtils'; import { isNumber, isString } from '/@/utils/is'; @@ -173,8 +172,7 @@ export function useContentHeight( () => { calcContentHeight(); }, - 50, - { immediate: true }, + { wait: 50, immediate: true }, ); watch( () => [layoutFooterHeightRef.value], diff --git a/src/hooks/web/useTitle.ts b/src/hooks/web/useTitle.ts index a7f48d8..675a5db 100644 --- a/src/hooks/web/useTitle.ts +++ b/src/hooks/web/useTitle.ts @@ -4,7 +4,6 @@ import { useTitle as usePageTitle } from '@vueuse/core'; import { useGlobSetting } from '/@/hooks/setting'; import { useRouter } from 'vue-router'; import { useLocaleStore } from '/@/store/modules/locale'; - import { REDIRECT_NAME } from '/@/router/constant'; /** diff --git a/src/layouts/default/content/useContentViewHeight.ts b/src/layouts/default/content/useContentViewHeight.ts index f620a33..8dd63fa 100644 --- a/src/layouts/default/content/useContentViewHeight.ts +++ b/src/layouts/default/content/useContentViewHeight.ts @@ -1,6 +1,6 @@ import { ref, computed, unref } from 'vue'; import { createPageContext } from '/@/hooks/component/usePageContext'; -import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; +import { useWindowSizeFn } from '@vben/hooks'; const headerHeightRef = ref(0); const footerHeightRef = ref(0); @@ -26,8 +26,7 @@ export function useContentViewHeight() { () => { contentHeight.value = window.innerHeight; }, - 100, - { immediate: true }, + { wait: 100, immediate: true }, ); async function setPageHeight(height: number) { diff --git a/src/views/sys/iframe/index.vue b/src/views/sys/iframe/index.vue index 8e9129e..ebf9fc4 100644 --- a/src/views/sys/iframe/index.vue +++ b/src/views/sys/iframe/index.vue @@ -14,7 +14,7 @@ import type { CSSProperties } from 'vue'; import { ref, unref, computed } from 'vue'; import { Spin } from 'ant-design-vue'; - import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; + import { useWindowSizeFn } from '@vben/hooks'; import { propTypes } from '/@/utils/propTypes'; import { useDesign } from '/@/hooks/web/useDesign'; import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight'; @@ -30,7 +30,7 @@ const { headerHeightRef } = useLayoutHeight(); const { prefixCls } = useDesign('iframe-page'); - useWindowSizeFn(calcHeight, 150, { immediate: true }); + useWindowSizeFn(calcHeight, { wait: 150, immediate: true }); const getWrapStyle = computed((): CSSProperties => { return { -- libgit2 0.23.3