Browse Source

fix: scroll error

pull/2930/head^2
tanjinzhou 4 years ago
parent
commit
c579bb0ad5
  1. 53
      components/vc-virtual-list/List.jsx
  2. 5
      components/vc-virtual-list/ScrollBar.jsx
  3. 18
      components/vc-virtual-list/hooks/useDiffItem.js
  4. 9
      components/vc-virtual-list/hooks/useMobileTouchMove.js
  5. 15
      components/vc-virtual-list/hooks/useOriginScroll.js
  6. 7
      components/vc-virtual-list/hooks/useScrollTo.jsx

53
components/vc-virtual-list/List.jsx

@ -3,12 +3,11 @@ import Item from './Item';
import ScrollBar from './ScrollBar';
import useHeights from './hooks/useHeights';
import useScrollTo from './hooks/useScrollTo';
// import useDiffItem from './hooks/useDiffItem';
import useFrameWheel from './hooks/useFrameWheel';
import useMobileTouchMove from './hooks/useMobileTouchMove';
import useOriginScroll from './hooks/useOriginScroll';
import PropTypes from '../_util/vue-types';
import { computed, nextTick, reactive, ref, watchEffect } from 'vue';
import { computed, nextTick, reactive, watchEffect } from 'vue';
import classNames from '../_util/classNames';
import createRef from '../_util/createRef';
@ -40,7 +39,7 @@ const ListProps = {
height: PropTypes.number,
itemHeight: PropTypes.number,
/** If not match virtual scroll condition, Set List still use height of container. */
fullHeight: PropTypes.bool,
fullHeight: PropTypes.bool.def(true),
itemKey: PropTypes.any,
component: PropTypes.any,
/** Set `false` will always use real scroll instead of virtual one */
@ -92,18 +91,13 @@ const List = {
const alignedTop = keepInRange(value);
componentRef.current.scrollTop = alignedTop;
if (componentRef.current) {
componentRef.current.scrollTop = alignedTop;
}
state.scrollTop = alignedTop;
}
// ================================ Legacy ================================
// Put ref here since the range is generate by follow
const rangeRef = ref({ start: 0, end: state.mergedData.length });
// const diffItemRef = ref();
// const [diffItem] = useDiffItem(mergedData, getKey);
// diffItemRef.current = diffItem;
// ================================ Height ================================
const [setInstance, collectHeight, heights] = useHeights(getKey, null, null);
@ -130,7 +124,6 @@ const List = {
const currentItemBottom =
itemTop + (cacheHeight === undefined ? props.itemHeight : cacheHeight);
// Check item top in the range
if (currentItemBottom >= state.scrollTop && startIndex === undefined) {
startIndex = i;
startOffset = itemTop;
@ -156,8 +149,6 @@ const List = {
// Give cache to improve scroll experience
endIndex = Math.min(endIndex + 1, state.mergedData.length);
rangeRef.value.start = startIndex;
rangeRef.value.end = endIndex;
return {
scrollHeight: itemTop,
start: startIndex,
@ -166,7 +157,7 @@ const List = {
};
});
// =============================== In Range ===============================
const maxScrollHeight = computed(() => calRes.scrollHeight - props.height);
const maxScrollHeight = computed(() => calRes.value.scrollHeight - props.height);
function keepInRange(newScrollTop) {
let newTop = Math.max(newScrollTop, 0);
@ -223,29 +214,29 @@ const List = {
});
watchEffect(() => {
nextTick(() => {
componentRef.current.removeEventListener('wheel', onRawWheel);
componentRef.current.removeEventListener('DOMMouseScroll', onFireFoxScroll);
componentRef.current.removeEventListener('MozMousePixelScroll', onMozMousePixelScroll);
// Firefox only
function onMozMousePixelScroll(e) {
if (inVirtual.value) {
e.preventDefault();
if (componentRef.current) {
// Firefox only
function onMozMousePixelScroll(e) {
if (inVirtual.value) {
e.preventDefault();
}
}
componentRef.current.removeEventListener('wheel', onRawWheel);
componentRef.current.removeEventListener('DOMMouseScroll', onFireFoxScroll);
componentRef.current.removeEventListener('MozMousePixelScroll', onMozMousePixelScroll);
componentRef.current.addEventListener('wheel', onRawWheel);
componentRef.current.addEventListener('DOMMouseScroll', onFireFoxScroll);
componentRef.current.addEventListener('MozMousePixelScroll', onMozMousePixelScroll);
}
componentRef.current.addEventListener('wheel', onRawWheel);
componentRef.current.addEventListener('DOMMouseScroll', onFireFoxScroll);
componentRef.current.addEventListener('MozMousePixelScroll', onMozMousePixelScroll);
});
});
// ================================= Ref ==================================
const scrollTo = useScrollTo(
componentRef,
state.mergedData,
state,
heights,
props.itemHeight,
props,
getKey,
collectHeight,
syncScrollTop,
@ -288,7 +279,7 @@ const List = {
height,
itemHeight,
// eslint-disable-next-line no-unused-vars
fullHeight = true,
fullHeight,
data,
itemKey,
virtual,

5
components/vc-virtual-list/ScrollBar.jsx

@ -76,8 +76,10 @@ export default {
delayHidden() {
clearTimeout(this.visibleTimeout);
this.state.visible = true;
this.visibleTimeout = setTimeout(() => {
this.state.visible = false;
this.$forceUpdate(); // why ?
}, 2000);
},
@ -191,7 +193,6 @@ export default {
const { prefixCls } = this.$props;
const spinHeight = this.getSpinHeight() + 'px';
const top = this.getTop() + 'px';
return (
<div
ref={this.scrollbarRef}
@ -202,7 +203,7 @@ export default {
bottom: 0,
right: 0,
position: 'absolute',
// display: visible ? null : 'none',
display: visible ? null : 'none',
}}
onMousedown={this.onContainerMouseDown}
onMousemove={this.delayHidden}

18
components/vc-virtual-list/hooks/useDiffItem.js

@ -1,18 +0,0 @@
import { ref, toRaw, watch } from 'vue';
import cloneDeep from 'lodash-es/cloneDeep';
import { findListDiffIndex } from '../utils/algorithmUtil';
export default function useDiffItem(data, getKey, onDiff) {
const diffItem = ref(null);
let prevData = cloneDeep(toRaw(data));
watch(data, val => {
const diff = findListDiffIndex(prevData || [], val || [], getKey);
if (diff?.index !== undefined) {
onDiff?.(diff.index);
diffItem = val[diff.index];
}
prevData = cloneDeep(toRaw(val));
});
return [diffItem];
}

9
components/vc-virtual-list/hooks/useMobileTouchMove.js

@ -61,14 +61,11 @@ export default function useMobileTouchMove(inVirtual, listRef, callback) {
}
};
watch(inVirtual, val => {
listRef.current.removeEventListener('touchstart', onTouchStart);
cleanUpEvents();
clearInterval(interval);
if (val.value) {
listRef.current.addEventListener('touchstart', onTouchStart);
}
return () => {
listRef.current.removeEventListener('touchstart', onTouchStart);
cleanUpEvents();
clearInterval(interval);
};
});
}

15
components/vc-virtual-list/hooks/useOriginScroll.js

@ -1,5 +1,3 @@
import { reactive } from 'vue';
export default (isScrollAtTop, isScrollAtBottom) => {
// Do lock for a wheel when scrolling
let lock = false;
@ -13,21 +11,12 @@ export default (isScrollAtTop, isScrollAtBottom) => {
lock = false;
}, 50);
}
// Pass to ref since global add is in closure
const scrollPingRef = reactive({
top: isScrollAtTop.value,
bottom: isScrollAtBottom.value,
});
// scrollPingRef.value.top = isScrollAtTop;
// scrollPingRef.value.bottom = isScrollAtBottom;
return (deltaY, smoothOffset = false) => {
const originScroll =
// Pass origin wheel when on the top
(deltaY < 0 && scrollPingRef.top) ||
(deltaY < 0 && isScrollAtTop.value) ||
// Pass origin wheel when on the bottom
(deltaY > 0 && scrollPingRef.bottom);
(deltaY > 0 && isScrollAtBottom.value);
if (smoothOffset && originScroll) {
// No need lock anymore when it's smooth offset from touchMove interval

7
components/vc-virtual-list/hooks/useScrollTo.jsx

@ -4,9 +4,9 @@ import raf from '../../_util/raf';
export default function useScrollTo(
containerRef,
data,
state,
heights,
itemHeight,
props,
getKey,
collectHeight,
syncScrollTop,
@ -15,7 +15,8 @@ export default function useScrollTo(
return arg => {
raf.cancel(scroll);
const data = state.mergedData;
const itemHeight = props.itemHeight;
if (typeof arg === 'number') {
syncScrollTop(arg);
} else if (arg && typeof arg === 'object') {

Loading…
Cancel
Save