mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
chore(Sticky): improve code style (#8270)
This commit is contained in:
parent
bf56901fa1
commit
059ed39135
@ -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>
|
||||||
};
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -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(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user