fix: scroll error

pull/2930/head^2
tanjinzhou 2020-09-29 15:16:56 +08:00
parent 0de3e6b716
commit c579bb0ad5
6 changed files with 34 additions and 73 deletions

View File

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

View File

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

View File

@ -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];
}

View File

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

View File

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

View File

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