diff --git a/src/collapse-item/index.js b/src/collapse-item/index.js index 1340dc2b4..57dadf2bd 100644 --- a/src/collapse-item/index.js +++ b/src/collapse-item/index.js @@ -41,7 +41,7 @@ export default createComponent({ }); const show = ref(expanded.value); - const shouldRender = useLazyRender(show); + const lazyRender = useLazyRender(show); const onTransitionEnd = () => { if (!expanded.value) { @@ -115,22 +115,18 @@ export default createComponent({ ); }; - const renderContent = () => { - if (shouldRender.value) { - return ( -
-
- {slots.default?.()} -
-
- ); - } - }; + const renderContent = lazyRender(() => ( +
+
+ {slots.default?.()} +
+
+ )); return () => (
diff --git a/src/composition/use-lazy-render.ts b/src/composition/use-lazy-render.ts index 26e902cd2..dcecc2771 100644 --- a/src/composition/use-lazy-render.ts +++ b/src/composition/use-lazy-render.ts @@ -1,13 +1,17 @@ -import { ref, isRef, watch, WatchSource } from 'vue'; +import { ref, watch, WatchSource, VNode } from 'vue'; export function useLazyRender(show: WatchSource) { - const inited = ref(isRef(show) ? show.value : show()); + const inited = ref(false); - watch(show, (value) => { - if (value) { - inited.value = value; - } - }); + watch( + show, + (value) => { + if (value) { + inited.value = value; + } + }, + { immediate: true } + ); - return inited; + return (render: () => VNode) => () => (inited.value ? render() : null); } diff --git a/src/composition/use-lock-scroll.ts b/src/composition/use-lock-scroll.ts index 41d2da242..c64e9edf6 100644 --- a/src/composition/use-lock-scroll.ts +++ b/src/composition/use-lock-scroll.ts @@ -1,55 +1,25 @@ -import { useTouch } from './use-touch'; -import { getScroller } from '../utils/dom/scroll'; -import { on, off, preventDefault } from '../utils/dom/event'; - let count = 0; + const CLASSNAME = 'van-overflow-hidden'; -export function useLockScroll(element: HTMLElement) { - const { start, move, deltaY, direction } = useTouch(); - - const onTouchMove = ((event: TouchEvent) => { - move(event); - - if (direction.value !== 'vertical') { - return; - } - - let prevent = false; - const up = deltaY.value < 0; - const scroller = getScroller(event.target as HTMLElement, element); - const { scrollTop, scrollHeight, offsetHeight } = scroller as HTMLElement; - - if (scrollTop === 0) { - prevent = up && offsetHeight < scrollHeight; - } else if (scrollTop + offsetHeight >= scrollHeight) { - prevent = !up; - } - - if (prevent) { - preventDefault(event, true); - } - }) as EventListener; - +export function useLockScroll(shouldLock: () => boolean) { const lock = () => { - if (!count) { - document.body.classList.add(CLASSNAME); - } - - count++; - on(document, 'touchstart', start); - on(document, 'touchmove', onTouchMove); - }; - - lock(); - - return function unlock() { - count--; - off(document, 'touchstart', start); - off(document, 'touchmove', onTouchMove); - - if (!count) { - document.body.classList.remove(CLASSNAME); + if (shouldLock()) { + if (!count) { + document.body.classList.add(CLASSNAME); + } + count++; } }; + + const unlock = () => { + if (shouldLock() && count) { + count--; + if (!count) { + document.body.classList.remove(CLASSNAME); + } + } + }; + + return [lock, unlock]; } diff --git a/src/popup/index.js b/src/popup/index.js index fadbdaac1..34b5daeeb 100644 --- a/src/popup/index.js +++ b/src/popup/index.js @@ -3,6 +3,7 @@ import { ref, watch, Teleport, + computed, onMounted, Transition, onActivated, @@ -12,6 +13,7 @@ import { import { createNamespace, isDef } from '../utils'; // Composition +import { useLockScroll } from '../composition/use-lock-scroll'; import { useLazyRender } from '../composition/use-lazy-render'; import { CloseOnPopstateMixin } from '../mixins/close-on-popstate'; @@ -106,39 +108,36 @@ export default createComponent({ const zIndex = ref(); - const shouldRender = useLazyRender(() => props.show || !props.lazyRender); + const [lockScroll, unlockScroll] = useLockScroll(() => props.lockScroll); - const lockScroll = () => { - if (props.lockScroll) { - if (!context.lockCount) { - document.body.classList.add('van-overflow-hidden'); - } - context.lockCount++; + const lazyRender = useLazyRender(() => props.show || !props.lazyRender); + + const style = computed(() => { + const style = { + zIndex: zIndex.value, + }; + + if (isDef(props.duration)) { + const key = + props.position === 'center' + ? 'animationDuration' + : 'transitionDuration'; + style[key] = `${props.duration}s`; } - }; - const unlockScroll = () => { - if (props.lockScroll && context.lockCount) { - context.lockCount--; - - if (!context.lockCount) { - document.body.classList.remove('van-overflow-hidden'); - } - } - }; + return style; + }); const open = () => { - if (opened) { - return; - } + if (!opened) { + if (props.zIndex !== undefined) { + context.zIndex = props.zIndex; + } - if (props.zIndex !== undefined) { - context.zIndex = props.zIndex; + opened = true; + lockScroll(); + zIndex.value = ++context.zIndex; } - - opened = true; - lockScroll(); - zIndex.value = ++context.zIndex; }; const close = () => { @@ -151,7 +150,6 @@ export default createComponent({ const onClickOverlay = () => { emit('click-overlay'); - if (props.closeOnClickOverlay) { close(); } @@ -190,50 +188,38 @@ export default createComponent({ const onOpened = () => emit('opened'); const onClosed = () => emit('closed'); - const renderPopup = () => { - const { - round, - position, - duration, - transition, - safeAreaInsetBottom, - } = props; - const isCenter = position === 'center'; + const renderPopup = lazyRender(() => { + const { round, position, safeAreaInsetBottom } = props; + return ( +
+ {slots.default?.()} + {renderCloseIcon()} +
+ ); + }); - const transitionName = - transition || (isCenter ? 'van-fade' : `van-popup-slide-${position}`); - - const style = { - zIndex: zIndex.value, - }; - - if (isDef(duration)) { - const key = isCenter ? 'animationDuration' : 'transitionDuration'; - style[key] = `${duration}s`; - } + const renderTransition = () => { + const { position, transition } = props; + const name = + position === 'center' ? 'van-fade' : `van-popup-slide-${position}`; return ( - {shouldRender.value ? ( -
- {slots.default?.()} - {renderCloseIcon()} -
- ) : null} + {renderPopup()}
); }; @@ -282,7 +268,7 @@ export default createComponent({ return ( {renderOverlay()} - {renderPopup()} + {renderTransition()} ); } @@ -290,7 +276,7 @@ export default createComponent({ return ( <> {renderOverlay()} - {renderPopup()} + {renderTransition()} ); };