chore(Sticky): improve code style (#8270)

This commit is contained in:
neverland 2021-03-04 19:25:04 +08:00 committed by GitHub
parent bf56901fa1
commit 059ed39135
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 61 deletions

View File

@ -1,7 +1,13 @@
import { computed, CSSProperties, PropType, reactive, ref } from 'vue'; import { ref, computed, CSSProperties, PropType, reactive } from 'vue';
// Utils // Utils
import { createNamespace, getScrollTop, isHidden, unitToPx } from '../utils'; import {
isHidden,
unitToPx,
getScrollTop,
getZIndexStyle,
createNamespace,
} from '../utils';
// Composables // Composables
import { useRect, useEventListener, useScrollParent } from '@vant/use'; import { useRect, useEventListener, useScrollParent } from '@vant/use';
@ -9,12 +15,12 @@ import { useVisibilityChange } from '../composables/use-visibility-change';
const [createComponent, bem] = createNamespace('sticky'); const [createComponent, bem] = createNamespace('sticky');
export type Position = 'top' | 'bottom'; export type StickyPosition = 'top' | 'bottom';
export default createComponent({ export default createComponent({
props: { props: {
zIndex: [Number, String], zIndex: [Number, String],
container: null, container: Element,
offsetTop: { offsetTop: {
type: [Number, String], type: [Number, String],
default: 0, default: 0,
@ -24,7 +30,7 @@ export default createComponent({
default: 0, default: 0,
}, },
position: { position: {
type: String as PropType<Position>, type: String as PropType<StickyPosition>,
default: 'top', default: 'top',
}, },
}, },
@ -34,7 +40,6 @@ export default createComponent({
setup(props, { emit, slots }) { setup(props, { emit, slots }) {
const root = ref<HTMLElement>(); const root = ref<HTMLElement>();
const scrollParent = useScrollParent(root); const scrollParent = useScrollParent(root);
const state = reactive({ const state = reactive({
fixed: false, fixed: false,
width: 0, // root width width: 0, // root width
@ -42,104 +47,94 @@ export default createComponent({
transform: 0, transform: 0,
}); });
const offsetTop = computed(() => unitToPx(props.offsetTop)); const offset = computed(() =>
const offsetBottom = computed(() => unitToPx(props.offsetBottom)); unitToPx(props.position === 'top' ? props.offsetTop : props.offsetBottom)
);
const style = computed<CSSProperties | undefined>(() => { const rootStyle = computed<CSSProperties | undefined>(() => {
const { fixed, height, width } = state;
if (fixed) {
return {
width: `${width}px`,
height: `${height}px`,
};
}
});
const stickyStyle = computed<CSSProperties | undefined>(() => {
if (!state.fixed) { if (!state.fixed) {
return; return;
} }
const style: CSSProperties = { const style: CSSProperties = {
...getZIndexStyle(props.zIndex),
width: `${state.width}px`, width: `${state.width}px`,
height: `${state.height}px`, height: `${state.height}px`,
[props.position]: `${offset.value}px`,
}; };
if (state.transform) { if (state.transform) {
style.transform = `translate3d(0, ${state.transform}px, 0)`; style.transform = `translate3d(0, ${state.transform}px, 0)`;
} }
if (props.zIndex !== undefined) {
style.zIndex = +props.zIndex;
}
if (props.position === 'top') {
style.top = offsetTop.value ? `${offsetTop.value}px` : 0;
} else {
style.bottom = offsetBottom.value ? `${offsetBottom.value}px` : 0;
}
return style; return style;
}); });
const emitScrollEvent = (scrollTop: number) => { const emitScroll = (scrollTop: number) =>
emit('scroll', { emit('scroll', {
scrollTop, scrollTop,
isFixed: state.fixed, isFixed: state.fixed,
}); });
};
const onScroll = () => { const onScroll = () => {
if (!root.value || isHidden(root)) { if (!root.value || isHidden(root)) {
return; return;
} }
const { container } = props; const { container, position } = props;
const rootRect = useRect(root); const rootRect = useRect(root);
const containerRect = container?.getBoundingClientRect(); const scrollTop = getScrollTop(window);
state.width = rootRect.width; state.width = rootRect.width;
state.height = rootRect.height; state.height = rootRect.height;
const scrollTop = getScrollTop(window); if (position === 'top') {
if (props.position === 'top') {
// The sticky component should be kept inside the container element // The sticky component should be kept inside the container element
if (container) { if (container) {
const difference = const containerRect = useRect(container);
containerRect.bottom - offsetTop.value - state.height; const difference = containerRect.bottom - offset.value - state.height;
state.fixed = state.fixed = offset.value > rootRect.top && containerRect.bottom > 0;
offsetTop.value > rootRect.top && containerRect.bottom > 0;
state.transform = difference < 0 ? difference : 0; state.transform = difference < 0 ? difference : 0;
} else { } else {
state.fixed = offsetTop.value > rootRect.top; state.fixed = offset.value > rootRect.top;
} }
} else if (props.position === 'bottom') { } else {
const { clientHeight } = document.documentElement; const { clientHeight } = document.documentElement;
if (container) { if (container) {
const containerRect = useRect(container);
const difference = const difference =
clientHeight - clientHeight - containerRect.top - offset.value - state.height;
containerRect.top -
offsetBottom.value -
state.height;
state.fixed = state.fixed =
clientHeight - offsetBottom.value < rootRect.bottom && clientHeight - offset.value < rootRect.bottom &&
clientHeight > containerRect.top; clientHeight > containerRect.top;
state.transform = difference < 0 ? -difference : 0; state.transform = difference < 0 ? -difference : 0;
} else { } else {
state.fixed = clientHeight - offsetBottom.value < rootRect.bottom; state.fixed = clientHeight - offset.value < rootRect.bottom;
} }
} }
emitScrollEvent(scrollTop);
emitScroll(scrollTop);
}; };
useEventListener('scroll', onScroll, { target: scrollParent }); useEventListener('scroll', onScroll, { target: scrollParent });
useVisibilityChange(root, onScroll); useVisibilityChange(root, onScroll);
return () => { return () => (
const { fixed, height, width } = state; <div ref={root} style={rootStyle.value}>
const rootStyle: CSSProperties = { <div class={bem({ fixed: state.fixed })} style={stickyStyle.value}>
width: fixed ? `${width}px` : undefined, {slots.default?.()}
height: fixed ? `${height}px` : undefined,
};
return (
<div ref={root} style={rootStyle}>
<div class={bem({ fixed })} style={style.value}>
{slots.default?.()}
</div>
</div> </div>
); </div>
}; );
}, },
}); });

View File

@ -391,6 +391,7 @@ export default createComponent({
const style: CSSProperties = { const style: CSSProperties = {
backgroundColor: active ? props.indicatorColor : undefined, backgroundColor: active ? props.indicatorColor : undefined,
}; };
return <i style={style} class={bem('indicator', { active })} />; return <i style={style} class={bem('indicator', { active })} />;
}; };
@ -401,7 +402,7 @@ export default createComponent({
if (props.showIndicators && count.value > 1) { if (props.showIndicators && count.value > 1) {
return ( return (
<div class={bem('indicators', { vertical: props.vertical })}> <div class={bem('indicators', { vertical: props.vertical })}>
{Array(...Array(count.value)).map(renderDot)} {Array(count.value).fill('').map(renderDot)}
</div> </div>
); );
} }
@ -415,19 +416,21 @@ export default createComponent({
swipeTo, swipeTo,
}); });
linkChildren({ size, props, count, activeIndicator }); linkChildren({
size,
props,
count,
activeIndicator,
});
watch( watch(
() => props.initialSwipe, () => props.initialSwipe,
(value) => { (value) => initialize(+value)
initialize(+value);
}
); );
watch( watch(
() => children.length, () => children.length,
() => { () => initialize(state.active)
initialize(state.active);
}
); );
watch( watch(