chore: adjust useLockScroll、useLazyRender

This commit is contained in:
chenjiahan 2020-09-14 20:32:58 +08:00
parent 708c37c759
commit a4743fa648
4 changed files with 95 additions and 139 deletions

View File

@ -41,7 +41,7 @@ export default createComponent({
}); });
const show = ref(expanded.value); const show = ref(expanded.value);
const shouldRender = useLazyRender(show); const lazyRender = useLazyRender(show);
const onTransitionEnd = () => { const onTransitionEnd = () => {
if (!expanded.value) { if (!expanded.value) {
@ -115,22 +115,18 @@ export default createComponent({
); );
}; };
const renderContent = () => { const renderContent = lazyRender(() => (
if (shouldRender.value) { <div
return ( ref={wrapperRef}
<div vShow={show.value}
ref={wrapperRef} class={bem('wrapper')}
vShow={show.value} onTransitionend={onTransitionEnd}
class={bem('wrapper')} >
onTransitionend={onTransitionEnd} <div ref={contentRef} class={bem('content')}>
> {slots.default?.()}
<div ref={contentRef} class={bem('content')}> </div>
{slots.default?.()} </div>
</div> ));
</div>
);
}
};
return () => ( return () => (
<div class={[bem({ border: index.value && props.border })]}> <div class={[bem({ border: index.value && props.border })]}>

View File

@ -1,13 +1,17 @@
import { ref, isRef, watch, WatchSource } from 'vue'; import { ref, watch, WatchSource, VNode } from 'vue';
export function useLazyRender(show: WatchSource<boolean>) { export function useLazyRender(show: WatchSource<boolean>) {
const inited = ref(isRef(show) ? show.value : show()); const inited = ref(false);
watch(show, (value) => { watch(
if (value) { show,
inited.value = value; (value) => {
} if (value) {
}); inited.value = value;
}
},
{ immediate: true }
);
return inited; return (render: () => VNode) => () => (inited.value ? render() : null);
} }

View File

@ -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; let count = 0;
const CLASSNAME = 'van-overflow-hidden'; const CLASSNAME = 'van-overflow-hidden';
export function useLockScroll(element: HTMLElement) { export function useLockScroll(shouldLock: () => boolean) {
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;
const lock = () => { const lock = () => {
if (!count) { if (shouldLock()) {
document.body.classList.add(CLASSNAME); if (!count) {
} document.body.classList.add(CLASSNAME);
}
count++; 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);
} }
}; };
const unlock = () => {
if (shouldLock() && count) {
count--;
if (!count) {
document.body.classList.remove(CLASSNAME);
}
}
};
return [lock, unlock];
} }

View File

@ -3,6 +3,7 @@ import {
ref, ref,
watch, watch,
Teleport, Teleport,
computed,
onMounted, onMounted,
Transition, Transition,
onActivated, onActivated,
@ -12,6 +13,7 @@ import {
import { createNamespace, isDef } from '../utils'; import { createNamespace, isDef } from '../utils';
// Composition // Composition
import { useLockScroll } from '../composition/use-lock-scroll';
import { useLazyRender } from '../composition/use-lazy-render'; import { useLazyRender } from '../composition/use-lazy-render';
import { CloseOnPopstateMixin } from '../mixins/close-on-popstate'; import { CloseOnPopstateMixin } from '../mixins/close-on-popstate';
@ -106,39 +108,36 @@ export default createComponent({
const zIndex = ref(); const zIndex = ref();
const shouldRender = useLazyRender(() => props.show || !props.lazyRender); const [lockScroll, unlockScroll] = useLockScroll(() => props.lockScroll);
const lockScroll = () => { const lazyRender = useLazyRender(() => props.show || !props.lazyRender);
if (props.lockScroll) {
if (!context.lockCount) { const style = computed(() => {
document.body.classList.add('van-overflow-hidden'); const style = {
} zIndex: zIndex.value,
context.lockCount++; };
if (isDef(props.duration)) {
const key =
props.position === 'center'
? 'animationDuration'
: 'transitionDuration';
style[key] = `${props.duration}s`;
} }
};
const unlockScroll = () => { return style;
if (props.lockScroll && context.lockCount) { });
context.lockCount--;
if (!context.lockCount) {
document.body.classList.remove('van-overflow-hidden');
}
}
};
const open = () => { const open = () => {
if (opened) { if (!opened) {
return; if (props.zIndex !== undefined) {
} context.zIndex = props.zIndex;
}
if (props.zIndex !== undefined) { opened = true;
context.zIndex = props.zIndex; lockScroll();
zIndex.value = ++context.zIndex;
} }
opened = true;
lockScroll();
zIndex.value = ++context.zIndex;
}; };
const close = () => { const close = () => {
@ -151,7 +150,6 @@ export default createComponent({
const onClickOverlay = () => { const onClickOverlay = () => {
emit('click-overlay'); emit('click-overlay');
if (props.closeOnClickOverlay) { if (props.closeOnClickOverlay) {
close(); close();
} }
@ -190,50 +188,38 @@ export default createComponent({
const onOpened = () => emit('opened'); const onOpened = () => emit('opened');
const onClosed = () => emit('closed'); const onClosed = () => emit('closed');
const renderPopup = () => { const renderPopup = lazyRender(() => {
const { const { round, position, safeAreaInsetBottom } = props;
round, return (
position, <div
duration, vShow={props.show}
transition, style={style.value}
safeAreaInsetBottom, class={bem({
} = props; round,
const isCenter = position === 'center'; [position]: position,
'safe-area-inset-bottom': safeAreaInsetBottom,
})}
onClick={onClick}
{...attrs}
>
{slots.default?.()}
{renderCloseIcon()}
</div>
);
});
const transitionName = const renderTransition = () => {
transition || (isCenter ? 'van-fade' : `van-popup-slide-${position}`); const { position, transition } = props;
const name =
const style = { position === 'center' ? 'van-fade' : `van-popup-slide-${position}`;
zIndex: zIndex.value,
};
if (isDef(duration)) {
const key = isCenter ? 'animationDuration' : 'transitionDuration';
style[key] = `${duration}s`;
}
return ( return (
<Transition <Transition
name={transitionName} name={transition || name}
onAfterEnter={onOpened} onAfterEnter={onOpened}
onAfterLeave={onClosed} onAfterLeave={onClosed}
> >
{shouldRender.value ? ( {renderPopup()}
<div
vShow={props.show}
style={style}
class={bem({
round,
[position]: position,
'safe-area-inset-bottom': safeAreaInsetBottom,
})}
onClick={onClick}
{...attrs}
>
{slots.default?.()}
{renderCloseIcon()}
</div>
) : null}
</Transition> </Transition>
); );
}; };
@ -282,7 +268,7 @@ export default createComponent({
return ( return (
<Teleport to={props.teleport}> <Teleport to={props.teleport}>
{renderOverlay()} {renderOverlay()}
{renderPopup()} {renderTransition()}
</Teleport> </Teleport>
); );
} }
@ -290,7 +276,7 @@ export default createComponent({
return ( return (
<> <>
{renderOverlay()} {renderOverlay()}
{renderPopup()} {renderTransition()}
</> </>
); );
}; };