perf: update virtual-list
parent
a3a060077b
commit
2e61e9cb50
|
@ -5,7 +5,7 @@ import classNames from '../_util/classNames';
|
|||
import pickAttrs from '../_util/pickAttrs';
|
||||
import { isValidElement } from '../_util/props-util';
|
||||
import createRef from '../_util/createRef';
|
||||
import { computed, defineComponent, reactive, VNodeChild, watch } from 'vue';
|
||||
import { computed, defineComponent, nextTick, reactive, VNodeChild, watch } from 'vue';
|
||||
import List from '../vc-virtual-list/List';
|
||||
import {
|
||||
OptionsType as SelectOptionsType,
|
||||
|
@ -153,8 +153,14 @@ const OptionList = defineComponent<OptionListProps, { state?: any }>({
|
|||
scrollIntoView(index);
|
||||
}
|
||||
});
|
||||
// Force trigger scrollbar visible when open
|
||||
if (props.open) {
|
||||
nextTick(()=>{
|
||||
listRef.current?.scrollTo(undefined);
|
||||
})
|
||||
}
|
||||
},
|
||||
{ immediate: true, flush: 'post' },
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// ========================== Values ==========================
|
||||
|
|
|
@ -84,16 +84,13 @@ const List = defineComponent({
|
|||
},
|
||||
setup(props) {
|
||||
// ================================= MISC =================================
|
||||
|
||||
const useVirtual = computed(()=>{
|
||||
const { height, itemHeight, virtual } = props;
|
||||
return !!(virtual !== false && height && itemHeight);
|
||||
})
|
||||
const inVirtual = computed(() => {
|
||||
const { height, itemHeight, data, virtual } = props;
|
||||
return !!(
|
||||
virtual !== false &&
|
||||
height &&
|
||||
itemHeight &&
|
||||
data &&
|
||||
itemHeight * data.length > height
|
||||
);
|
||||
const { height, itemHeight, data } = props;
|
||||
return useVirtual.value && data && itemHeight * data.length > height;
|
||||
});
|
||||
|
||||
const state = reactive<ListState>({
|
||||
|
@ -103,7 +100,8 @@ const List = defineComponent({
|
|||
});
|
||||
|
||||
const componentRef = ref<HTMLDivElement>();
|
||||
|
||||
const fillerInnerRef = ref<HTMLDivElement>();
|
||||
const scrollBarRef = ref<any>(); // Hack on scrollbar to enable flash call
|
||||
// =============================== Item Key ===============================
|
||||
const getKey = (item: Record<string, any>) => {
|
||||
if (typeof props.itemKey === 'function') {
|
||||
|
@ -135,10 +133,9 @@ const List = defineComponent({
|
|||
|
||||
// ================================ Height ================================
|
||||
const [setInstance, collectHeight, heights, heightUpdatedMark] = useHeights(getKey, null, null);
|
||||
|
||||
// ========================== Visible Calculation =========================
|
||||
const calRes = computed(() => {
|
||||
if (!inVirtual.value) {
|
||||
if (!useVirtual.value) {
|
||||
return {
|
||||
scrollHeight: undefined,
|
||||
start: 0,
|
||||
|
@ -146,6 +143,17 @@ const List = defineComponent({
|
|||
offset: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
// Always use virtual scroll bar in avoid shaking
|
||||
if (!inVirtual.value) {
|
||||
return {
|
||||
scrollHeight: fillerInnerRef.value?.offsetHeight || 0,
|
||||
start: 0,
|
||||
end: state.mergedData.length - 1,
|
||||
offset: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
let itemTop = 0;
|
||||
let startIndex: number | undefined;
|
||||
let startOffset: number | undefined;
|
||||
|
@ -228,7 +236,7 @@ const List = defineComponent({
|
|||
|
||||
// Since this added in global,should use ref to keep update
|
||||
const [onRawWheel, onFireFoxScroll] = useFrameWheel(
|
||||
inVirtual,
|
||||
useVirtual,
|
||||
isScrollAtTop,
|
||||
isScrollAtBottom,
|
||||
offsetY => {
|
||||
|
@ -240,7 +248,7 @@ const List = defineComponent({
|
|||
);
|
||||
|
||||
// Mobile touch move
|
||||
useMobileTouchMove(inVirtual, componentRef, (deltaY, smoothOffset) => {
|
||||
useMobileTouchMove(useVirtual, componentRef, (deltaY, smoothOffset) => {
|
||||
if (originScroll(deltaY, smoothOffset)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -250,7 +258,7 @@ const List = defineComponent({
|
|||
});
|
||||
// Firefox only
|
||||
function onMozMousePixelScroll(e: MouseEvent) {
|
||||
if (inVirtual.value) {
|
||||
if (useVirtual.value) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
@ -285,6 +293,9 @@ const List = defineComponent({
|
|||
getKey,
|
||||
collectHeight,
|
||||
syncScrollTop,
|
||||
() => {
|
||||
scrollBarRef.value?.delayHidden();
|
||||
},
|
||||
);
|
||||
|
||||
const componentStyle = computed(() => {
|
||||
|
@ -292,7 +303,7 @@ const List = defineComponent({
|
|||
if (props.height) {
|
||||
cs = { [props.fullHeight ? 'height' : 'maxHeight']: props.height + 'px', ...ScrollStyle };
|
||||
|
||||
if (inVirtual.value) {
|
||||
if (useVirtual.value) {
|
||||
cs!.overflowY = 'hidden';
|
||||
|
||||
if (state.scrollMoving) {
|
||||
|
@ -310,11 +321,13 @@ const List = defineComponent({
|
|||
onFallbackScroll,
|
||||
onScrollBar,
|
||||
componentRef,
|
||||
inVirtual,
|
||||
useVirtual,
|
||||
calRes,
|
||||
collectHeight,
|
||||
setInstance,
|
||||
sharedConfig,
|
||||
scrollBarRef,
|
||||
fillerInnerRef
|
||||
};
|
||||
},
|
||||
render() {
|
||||
|
@ -341,7 +354,7 @@ const List = defineComponent({
|
|||
componentStyle,
|
||||
onFallbackScroll,
|
||||
onScrollBar,
|
||||
inVirtual,
|
||||
useVirtual,
|
||||
collectHeight,
|
||||
sharedConfig,
|
||||
setInstance,
|
||||
|
@ -375,13 +388,15 @@ const List = defineComponent({
|
|||
height={scrollHeight}
|
||||
offset={offset}
|
||||
onInnerResize={collectHeight}
|
||||
ref="fillerInnerRef"
|
||||
>
|
||||
{listChildren}
|
||||
</Filler>
|
||||
</Component>
|
||||
|
||||
{inVirtual && (
|
||||
{useVirtual && (
|
||||
<ScrollBar
|
||||
ref="scrollBarRef"
|
||||
prefixCls={prefixCls}
|
||||
scrollTop={scrollTop}
|
||||
height={height}
|
||||
|
|
|
@ -137,7 +137,7 @@ export default defineComponent({
|
|||
const enableScrollRange = this.getEnableScrollRange();
|
||||
const enableHeightRange = this.getEnableHeightRange();
|
||||
|
||||
const ptg = newTop / enableHeightRange;
|
||||
const ptg = enableHeightRange ? newTop / enableHeightRange : 0;
|
||||
const newScrollTop = Math.ceil(ptg * enableScrollRange);
|
||||
this.moveRaf = raf(() => {
|
||||
onScroll(newScrollTop);
|
||||
|
@ -164,30 +164,45 @@ export default defineComponent({
|
|||
|
||||
getEnableScrollRange() {
|
||||
const { scrollHeight, height } = this.$props;
|
||||
return scrollHeight - height;
|
||||
return scrollHeight - height || 0;
|
||||
},
|
||||
|
||||
getEnableHeightRange() {
|
||||
const { height } = this.$props;
|
||||
const spinHeight = this.getSpinHeight();
|
||||
return height - spinHeight;
|
||||
return height - spinHeight || 0;
|
||||
},
|
||||
|
||||
getTop() {
|
||||
const { scrollTop } = this.$props;
|
||||
const enableScrollRange = this.getEnableScrollRange();
|
||||
const enableHeightRange = this.getEnableHeightRange();
|
||||
if (scrollTop === 0 || enableScrollRange === 0) {
|
||||
return 0;
|
||||
}
|
||||
const ptg = scrollTop / enableScrollRange;
|
||||
return ptg * enableHeightRange;
|
||||
},
|
||||
// Not show scrollbar when height is large thane scrollHeight
|
||||
getVisible () {
|
||||
const { visible } = this.state;
|
||||
const { height, scrollHeight } = this.$props;
|
||||
|
||||
if (height >= scrollHeight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return visible;
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { visible, dragging } = this.state;
|
||||
const { dragging } = this.state;
|
||||
const { prefixCls } = this.$props;
|
||||
const spinHeight = this.getSpinHeight() + 'px';
|
||||
const top = this.getTop() + 'px';
|
||||
const visible = this.getVisible();
|
||||
return (
|
||||
<div
|
||||
ref={this.scrollbarRef}
|
||||
|
|
|
@ -12,10 +12,18 @@ export default function useScrollTo(
|
|||
getKey: GetKey,
|
||||
collectHeight: () => void,
|
||||
syncScrollTop: (newTop: number) => void,
|
||||
triggerFlash: () => void,
|
||||
) {
|
||||
let scroll: number | null = null;
|
||||
|
||||
return (arg: any) => {
|
||||
return (arg?: any) => {
|
||||
// When not argument provided, we think dev may want to show the scrollbar
|
||||
if (arg === null || arg === undefined) {
|
||||
triggerFlash();
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal scroll logic
|
||||
raf.cancel(scroll!);
|
||||
const data = state.mergedData;
|
||||
const itemHeight = props.itemHeight;
|
||||
|
|
Loading…
Reference in New Issue