@v-c/virtual-list 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/List.cjs +18 -31
- package/dist/List.js +19 -32
- package/dist/hooks/useChildren.cjs +23 -0
- package/dist/hooks/useChildren.d.ts +3 -0
- package/dist/hooks/useChildren.js +21 -0
- package/dist/hooks/useDiffItem.cjs +9 -10
- package/dist/hooks/useDiffItem.d.ts +1 -1
- package/dist/hooks/useDiffItem.js +10 -11
- package/dist/hooks/useScrollTo.cjs +12 -6
- package/dist/hooks/useScrollTo.d.ts +3 -3
- package/dist/hooks/useScrollTo.js +12 -5
- package/dist/utils/algorithmUtil.cjs +46 -0
- package/dist/utils/algorithmUtil.d.ts +23 -0
- package/dist/utils/algorithmUtil.js +45 -0
- package/package.json +2 -2
package/dist/List.cjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
2
|
const require_rolldown_runtime = require("./_virtual/rolldown_runtime.cjs");
|
|
3
3
|
const require_Filler = require("./Filler.cjs");
|
|
4
|
-
const
|
|
4
|
+
const require_useChildren = require("./hooks/useChildren.cjs");
|
|
5
|
+
const require_useDiffItem = require("./hooks/useDiffItem.cjs");
|
|
5
6
|
const require_useFrameWheel = require("./hooks/useFrameWheel.cjs");
|
|
6
7
|
const require_useGetSize = require("./hooks/useGetSize.cjs");
|
|
7
8
|
const require_useHeights = require("./hooks/useHeights.cjs");
|
|
@@ -14,9 +15,6 @@ let vue = require("vue");
|
|
|
14
15
|
let __v_c_resize_observer = require("@v-c/resize-observer");
|
|
15
16
|
__v_c_resize_observer = require_rolldown_runtime.__toESM(__v_c_resize_observer);
|
|
16
17
|
let __v_c_util_dist_props_util = require("@v-c/util/dist/props-util");
|
|
17
|
-
function _isSlot(s) {
|
|
18
|
-
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !(0, vue.isVNode)(s);
|
|
19
|
-
}
|
|
20
18
|
var EMPTY_DATA = [];
|
|
21
19
|
var ScrollStyle = {
|
|
22
20
|
overflowY: "auto",
|
|
@@ -125,7 +123,6 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
125
123
|
fillerOffset.value = void 0;
|
|
126
124
|
return;
|
|
127
125
|
}
|
|
128
|
-
const { itemHeight: itemHeight$1, height } = props;
|
|
129
126
|
if (!inVirtual.value) {
|
|
130
127
|
scrollHeight.value = fillerInnerRef.value?.offsetHeight || 0;
|
|
131
128
|
start.value = 0;
|
|
@@ -133,6 +130,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
133
130
|
fillerOffset.value = void 0;
|
|
134
131
|
return;
|
|
135
132
|
}
|
|
133
|
+
const { itemHeight: itemHeight$1, height } = props;
|
|
136
134
|
let itemTop = 0;
|
|
137
135
|
let startIndex;
|
|
138
136
|
let startOffset;
|
|
@@ -258,6 +256,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
258
256
|
const onScrollbarStopMove = () => {
|
|
259
257
|
scrollMoving.value = false;
|
|
260
258
|
};
|
|
259
|
+
require_useDiffItem.default(mergedData, getKey);
|
|
261
260
|
(0, vue.watch)([
|
|
262
261
|
() => props.height,
|
|
263
262
|
scrollHeight,
|
|
@@ -266,7 +265,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
266
265
|
], () => {
|
|
267
266
|
if (inVirtual.value && props.height && scrollHeight.value) verticalScrollBarSpinSize.value = require_scrollbarUtil.getSpinSize(size.value.height, scrollHeight.value);
|
|
268
267
|
}, { immediate: true });
|
|
269
|
-
(0, vue.watch)([() => size.value.width,
|
|
268
|
+
(0, vue.watch)([() => size.value.width, contentScrollWidth], () => {
|
|
270
269
|
if (inVirtual.value && contentScrollWidth.value) horizontalScrollBarSpinSize.value = require_scrollbarUtil.getSpinSize(size.value.width, contentScrollWidth.value);
|
|
271
270
|
}, { immediate: true });
|
|
272
271
|
(0, vue.watch)(() => props.scrollWidth, (val) => {
|
|
@@ -279,7 +278,13 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
279
278
|
props.onScroll?.(e);
|
|
280
279
|
triggerScroll();
|
|
281
280
|
}
|
|
282
|
-
const scrollTo = require_useScrollTo.default(componentRef, mergedData, heights, itemHeight, getKey, () => collectHeight(true),
|
|
281
|
+
const [scrollTo, getTotalHeight] = require_useScrollTo.default(componentRef, mergedData, heights, itemHeight, getKey, () => collectHeight(true), (newTop) => {
|
|
282
|
+
const totalHeight = getTotalHeight();
|
|
283
|
+
const maxScrollHeight = Math.max(scrollHeight.value, totalHeight) - props.height;
|
|
284
|
+
const alignedTop = Math.max(0, Math.min(newTop, maxScrollHeight || 0));
|
|
285
|
+
if (componentRef.value) componentRef.value.scrollTop = alignedTop;
|
|
286
|
+
offsetTop.value = alignedTop;
|
|
287
|
+
}, delayHideScrollBar);
|
|
283
288
|
expose({
|
|
284
289
|
nativeElement: containerRef,
|
|
285
290
|
getScrollInfo: getVirtualScrollInfo,
|
|
@@ -304,30 +309,12 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
304
309
|
}
|
|
305
310
|
});
|
|
306
311
|
const getSize = require_useGetSize.useGetSize(mergedData, getKey, heights, itemHeight);
|
|
312
|
+
const listChildren = require_useChildren.default(mergedData, start, end, contentScrollWidth, offsetLeft, setInstanceRef, (item, index, props$1) => slots.default?.({
|
|
313
|
+
item,
|
|
314
|
+
index,
|
|
315
|
+
...props$1
|
|
316
|
+
}), { getKey });
|
|
307
317
|
return () => {
|
|
308
|
-
let _slot;
|
|
309
|
-
const renderChildren = () => {
|
|
310
|
-
const children = [];
|
|
311
|
-
const data = mergedData.value;
|
|
312
|
-
const defaultSlot = slots.default;
|
|
313
|
-
if (!defaultSlot) return children;
|
|
314
|
-
for (let i = start.value; i <= end.value; i += 1) {
|
|
315
|
-
const item = data[i];
|
|
316
|
-
const key = getKey(item);
|
|
317
|
-
const nodes = defaultSlot({
|
|
318
|
-
item,
|
|
319
|
-
index: i,
|
|
320
|
-
style: {},
|
|
321
|
-
offsetX: offsetLeft.value
|
|
322
|
-
});
|
|
323
|
-
const node = Array.isArray(nodes) ? nodes[0] : nodes;
|
|
324
|
-
if (node) children.push((0, vue.createVNode)(require_Item.default, {
|
|
325
|
-
"key": key,
|
|
326
|
-
"setRef": (ele) => setInstanceRef(item, ele)
|
|
327
|
-
}, _isSlot(node) ? node : { default: () => [node] }));
|
|
328
|
-
}
|
|
329
|
-
return children;
|
|
330
|
-
};
|
|
331
318
|
const componentStyle = {};
|
|
332
319
|
if (props.height) {
|
|
333
320
|
componentStyle[props.fullHeight ? "height" : "maxHeight"] = `${props.height}px`;
|
|
@@ -378,7 +365,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
378
365
|
"innerProps": props.innerProps,
|
|
379
366
|
"rtl": isRTL.value,
|
|
380
367
|
"extra": extraContent
|
|
381
|
-
},
|
|
368
|
+
}, { default: () => [listChildren.value] })] })] }),
|
|
382
369
|
inVirtual.value && scrollHeight.value > (props.height || 0) && (0, vue.createVNode)(require_ScrollBar.default, {
|
|
383
370
|
"ref": verticalScrollBarRef,
|
|
384
371
|
"prefixCls": props.prefixCls,
|
package/dist/List.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Filler_default from "./Filler.js";
|
|
2
|
-
import
|
|
2
|
+
import useChildren from "./hooks/useChildren.js";
|
|
3
|
+
import useDiffItem from "./hooks/useDiffItem.js";
|
|
3
4
|
import useFrameWheel from "./hooks/useFrameWheel.js";
|
|
4
5
|
import { useGetSize } from "./hooks/useGetSize.js";
|
|
5
6
|
import useHeights from "./hooks/useHeights.js";
|
|
@@ -8,12 +9,9 @@ import useScrollDrag from "./hooks/useScrollDrag.js";
|
|
|
8
9
|
import useScrollTo from "./hooks/useScrollTo.js";
|
|
9
10
|
import ScrollBar_default from "./ScrollBar.js";
|
|
10
11
|
import { getSpinSize } from "./utils/scrollbarUtil.js";
|
|
11
|
-
import { computed, createVNode, defineComponent,
|
|
12
|
+
import { computed, createVNode, defineComponent, mergeProps, ref, shallowRef, toRaw, toRef, watch } from "vue";
|
|
12
13
|
import ResizeObserver from "@v-c/resize-observer";
|
|
13
14
|
import { pureAttrs } from "@v-c/util/dist/props-util";
|
|
14
|
-
function _isSlot(s) {
|
|
15
|
-
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
16
|
-
}
|
|
17
15
|
var EMPTY_DATA = [];
|
|
18
16
|
var ScrollStyle = {
|
|
19
17
|
overflowY: "auto",
|
|
@@ -122,7 +120,6 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
122
120
|
fillerOffset.value = void 0;
|
|
123
121
|
return;
|
|
124
122
|
}
|
|
125
|
-
const { itemHeight: itemHeight$1, height } = props;
|
|
126
123
|
if (!inVirtual.value) {
|
|
127
124
|
scrollHeight.value = fillerInnerRef.value?.offsetHeight || 0;
|
|
128
125
|
start.value = 0;
|
|
@@ -130,6 +127,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
130
127
|
fillerOffset.value = void 0;
|
|
131
128
|
return;
|
|
132
129
|
}
|
|
130
|
+
const { itemHeight: itemHeight$1, height } = props;
|
|
133
131
|
let itemTop = 0;
|
|
134
132
|
let startIndex;
|
|
135
133
|
let startOffset;
|
|
@@ -255,6 +253,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
255
253
|
const onScrollbarStopMove = () => {
|
|
256
254
|
scrollMoving.value = false;
|
|
257
255
|
};
|
|
256
|
+
useDiffItem(mergedData, getKey);
|
|
258
257
|
watch([
|
|
259
258
|
() => props.height,
|
|
260
259
|
scrollHeight,
|
|
@@ -263,7 +262,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
263
262
|
], () => {
|
|
264
263
|
if (inVirtual.value && props.height && scrollHeight.value) verticalScrollBarSpinSize.value = getSpinSize(size.value.height, scrollHeight.value);
|
|
265
264
|
}, { immediate: true });
|
|
266
|
-
watch([() => size.value.width,
|
|
265
|
+
watch([() => size.value.width, contentScrollWidth], () => {
|
|
267
266
|
if (inVirtual.value && contentScrollWidth.value) horizontalScrollBarSpinSize.value = getSpinSize(size.value.width, contentScrollWidth.value);
|
|
268
267
|
}, { immediate: true });
|
|
269
268
|
watch(() => props.scrollWidth, (val) => {
|
|
@@ -276,7 +275,13 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
276
275
|
props.onScroll?.(e);
|
|
277
276
|
triggerScroll();
|
|
278
277
|
}
|
|
279
|
-
const scrollTo = useScrollTo(componentRef, mergedData, heights, itemHeight, getKey, () => collectHeight(true),
|
|
278
|
+
const [scrollTo, getTotalHeight] = useScrollTo(componentRef, mergedData, heights, itemHeight, getKey, () => collectHeight(true), (newTop) => {
|
|
279
|
+
const totalHeight = getTotalHeight();
|
|
280
|
+
const maxScrollHeight = Math.max(scrollHeight.value, totalHeight) - props.height;
|
|
281
|
+
const alignedTop = Math.max(0, Math.min(newTop, maxScrollHeight || 0));
|
|
282
|
+
if (componentRef.value) componentRef.value.scrollTop = alignedTop;
|
|
283
|
+
offsetTop.value = alignedTop;
|
|
284
|
+
}, delayHideScrollBar);
|
|
280
285
|
expose({
|
|
281
286
|
nativeElement: containerRef,
|
|
282
287
|
getScrollInfo: getVirtualScrollInfo,
|
|
@@ -301,30 +306,12 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
301
306
|
}
|
|
302
307
|
});
|
|
303
308
|
const getSize = useGetSize(mergedData, getKey, heights, itemHeight);
|
|
309
|
+
const listChildren = useChildren(mergedData, start, end, contentScrollWidth, offsetLeft, setInstanceRef, (item, index, props$1) => slots.default?.({
|
|
310
|
+
item,
|
|
311
|
+
index,
|
|
312
|
+
...props$1
|
|
313
|
+
}), { getKey });
|
|
304
314
|
return () => {
|
|
305
|
-
let _slot;
|
|
306
|
-
const renderChildren = () => {
|
|
307
|
-
const children = [];
|
|
308
|
-
const data = mergedData.value;
|
|
309
|
-
const defaultSlot = slots.default;
|
|
310
|
-
if (!defaultSlot) return children;
|
|
311
|
-
for (let i = start.value; i <= end.value; i += 1) {
|
|
312
|
-
const item = data[i];
|
|
313
|
-
const key = getKey(item);
|
|
314
|
-
const nodes = defaultSlot({
|
|
315
|
-
item,
|
|
316
|
-
index: i,
|
|
317
|
-
style: {},
|
|
318
|
-
offsetX: offsetLeft.value
|
|
319
|
-
});
|
|
320
|
-
const node = Array.isArray(nodes) ? nodes[0] : nodes;
|
|
321
|
-
if (node) children.push(createVNode(Item_default, {
|
|
322
|
-
"key": key,
|
|
323
|
-
"setRef": (ele) => setInstanceRef(item, ele)
|
|
324
|
-
}, _isSlot(node) ? node : { default: () => [node] }));
|
|
325
|
-
}
|
|
326
|
-
return children;
|
|
327
|
-
};
|
|
328
315
|
const componentStyle = {};
|
|
329
316
|
if (props.height) {
|
|
330
317
|
componentStyle[props.fullHeight ? "height" : "maxHeight"] = `${props.height}px`;
|
|
@@ -375,7 +362,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
375
362
|
"innerProps": props.innerProps,
|
|
376
363
|
"rtl": isRTL.value,
|
|
377
364
|
"extra": extraContent
|
|
378
|
-
},
|
|
365
|
+
}, { default: () => [listChildren.value] })] })] }),
|
|
379
366
|
inVirtual.value && scrollHeight.value > (props.height || 0) && createVNode(ScrollBar_default, {
|
|
380
367
|
"ref": verticalScrollBarRef,
|
|
381
368
|
"prefixCls": props.prefixCls,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
+
const require_rolldown_runtime = require("../_virtual/rolldown_runtime.cjs");
|
|
3
|
+
const require_Item = require("../Item.cjs");
|
|
4
|
+
let vue = require("vue");
|
|
5
|
+
function _isSlot(s) {
|
|
6
|
+
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !(0, vue.isVNode)(s);
|
|
7
|
+
}
|
|
8
|
+
function useChildren(list, startIndex, endIndex, scrollWidth, offsetX, setNodeRef, renderFunc, { getKey }) {
|
|
9
|
+
return (0, vue.computed)(() => {
|
|
10
|
+
return list.value.slice(startIndex.value, endIndex.value + 1).map((item, index) => {
|
|
11
|
+
const node = renderFunc(item, startIndex.value + index, {
|
|
12
|
+
style: { width: `${scrollWidth.value}px` },
|
|
13
|
+
offsetX: offsetX.value
|
|
14
|
+
});
|
|
15
|
+
const key = getKey(item);
|
|
16
|
+
return (0, vue.createVNode)(require_Item.default, {
|
|
17
|
+
"key": key,
|
|
18
|
+
"setRef": (ele) => setNodeRef(item, ele)
|
|
19
|
+
}, _isSlot(node) ? node : { default: () => [node] });
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
exports.default = useChildren;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { SharedConfig } from '../interface';
|
|
3
|
+
export default function useChildren(list: Ref<any[]>, startIndex: Ref<number>, endIndex: Ref<number>, scrollWidth: Ref<number>, offsetX: Ref<number>, setNodeRef: (item: any, element: HTMLElement | null) => void, renderFunc: any, { getKey }: SharedConfig<any>): import('vue').ComputedRef<import("vue/jsx-runtime").JSX.Element[]>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Item_default from "../Item.js";
|
|
2
|
+
import { computed, createVNode, isVNode } from "vue";
|
|
3
|
+
function _isSlot(s) {
|
|
4
|
+
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
5
|
+
}
|
|
6
|
+
function useChildren(list, startIndex, endIndex, scrollWidth, offsetX, setNodeRef, renderFunc, { getKey }) {
|
|
7
|
+
return computed(() => {
|
|
8
|
+
return list.value.slice(startIndex.value, endIndex.value + 1).map((item, index) => {
|
|
9
|
+
const node = renderFunc(item, startIndex.value + index, {
|
|
10
|
+
style: { width: `${scrollWidth.value}px` },
|
|
11
|
+
offsetX: offsetX.value
|
|
12
|
+
});
|
|
13
|
+
const key = getKey(item);
|
|
14
|
+
return createVNode(Item_default, {
|
|
15
|
+
"key": key,
|
|
16
|
+
"setRef": (ele) => setNodeRef(item, ele)
|
|
17
|
+
}, _isSlot(node) ? node : { default: () => [node] });
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export { useChildren as default };
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
2
|
const require_rolldown_runtime = require("../_virtual/rolldown_runtime.cjs");
|
|
3
|
+
const require_algorithmUtil = require("../utils/algorithmUtil.cjs");
|
|
3
4
|
let vue = require("vue");
|
|
4
|
-
function useDiffItem(data, getKey) {
|
|
5
|
-
const
|
|
6
|
-
const diffItem = (0, vue.
|
|
5
|
+
function useDiffItem(data, getKey, onDiff) {
|
|
6
|
+
const prevData = (0, vue.shallowRef)(data.value);
|
|
7
|
+
const diffItem = (0, vue.shallowRef)();
|
|
7
8
|
(0, vue.watch)(data, (newData) => {
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return !prevData.some((prevItem) => getKey(prevItem) === key);
|
|
13
|
-
});
|
|
14
|
-
prevDataRef.value = newData;
|
|
9
|
+
const diff = require_algorithmUtil.findListDiffIndex(prevData.value || [], data.value || [], getKey);
|
|
10
|
+
if (diff?.index !== void 0) {
|
|
11
|
+
onDiff?.(diff.index);
|
|
12
|
+
diffItem.value = newData[diff.index];
|
|
15
13
|
}
|
|
14
|
+
prevData.value = newData;
|
|
16
15
|
}, { immediate: true });
|
|
17
16
|
return diffItem;
|
|
18
17
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Ref } from 'vue';
|
|
2
|
-
export default function useDiffItem<T>(data: Ref<T[]>, getKey: (item: T) => any): Ref<T | undefined>;
|
|
2
|
+
export default function useDiffItem<T>(data: Ref<T[]>, getKey: (item: T) => any, onDiff?: (diffIndex: number) => void): Ref<T | undefined>;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
1
|
+
import { findListDiffIndex } from "../utils/algorithmUtil.js";
|
|
2
|
+
import { shallowRef, watch } from "vue";
|
|
3
|
+
function useDiffItem(data, getKey, onDiff) {
|
|
4
|
+
const prevData = shallowRef(data.value);
|
|
5
|
+
const diffItem = shallowRef();
|
|
5
6
|
watch(data, (newData) => {
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return !prevData.some((prevItem) => getKey(prevItem) === key);
|
|
11
|
-
});
|
|
12
|
-
prevDataRef.value = newData;
|
|
7
|
+
const diff = findListDiffIndex(prevData.value || [], data.value || [], getKey);
|
|
8
|
+
if (diff?.index !== void 0) {
|
|
9
|
+
onDiff?.(diff.index);
|
|
10
|
+
diffItem.value = newData[diff.index];
|
|
13
11
|
}
|
|
12
|
+
prevData.value = newData;
|
|
14
13
|
}, { immediate: true });
|
|
15
14
|
return diffItem;
|
|
16
15
|
}
|
|
@@ -2,13 +2,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
2
2
|
const require_rolldown_runtime = require("../_virtual/rolldown_runtime.cjs");
|
|
3
3
|
let vue = require("vue");
|
|
4
4
|
let __v_c_util = require("@v-c/util");
|
|
5
|
-
let __v_c_util_dist_raf = require("@v-c/util/dist/raf");
|
|
6
|
-
__v_c_util_dist_raf = require_rolldown_runtime.__toESM(__v_c_util_dist_raf);
|
|
7
5
|
var MAX_TIMES = 10;
|
|
8
6
|
function useScrollTo(containerRef, data, heights, itemHeight, getKey, collectHeight, syncScrollTop, triggerFlash) {
|
|
9
|
-
const scrollRef = (0, vue.shallowRef)();
|
|
10
7
|
const syncState = (0, vue.shallowRef)(null);
|
|
11
|
-
|
|
8
|
+
const getTotalHeight = () => {
|
|
9
|
+
let totalHeight = 0;
|
|
10
|
+
for (let i = 0; i < data.value.length; i += 1) {
|
|
11
|
+
const key = getKey(data.value[i]);
|
|
12
|
+
const cacheHeight = heights.get(key);
|
|
13
|
+
totalHeight += cacheHeight === void 0 ? itemHeight.value : cacheHeight;
|
|
14
|
+
}
|
|
15
|
+
return totalHeight;
|
|
16
|
+
};
|
|
17
|
+
(0, vue.watch)(syncState, () => {
|
|
12
18
|
if (syncState.value && syncState.value.times < MAX_TIMES) {
|
|
13
19
|
if (!containerRef.value) {
|
|
14
20
|
syncState.value = { ...syncState.value };
|
|
@@ -72,12 +78,11 @@ function useScrollTo(containerRef, data, heights, itemHeight, getKey, collectHei
|
|
|
72
78
|
immediate: true,
|
|
73
79
|
flush: "post"
|
|
74
80
|
});
|
|
75
|
-
|
|
81
|
+
const scrollTo = (arg) => {
|
|
76
82
|
if (arg === null || arg === void 0) {
|
|
77
83
|
triggerFlash();
|
|
78
84
|
return;
|
|
79
85
|
}
|
|
80
|
-
__v_c_util_dist_raf.default.cancel(scrollRef.value);
|
|
81
86
|
if (typeof arg === "number") syncScrollTop(arg);
|
|
82
87
|
else if (arg && typeof arg === "object") {
|
|
83
88
|
let index;
|
|
@@ -93,5 +98,6 @@ function useScrollTo(containerRef, data, heights, itemHeight, getKey, collectHei
|
|
|
93
98
|
};
|
|
94
99
|
}
|
|
95
100
|
};
|
|
101
|
+
return [scrollTo, getTotalHeight];
|
|
96
102
|
}
|
|
97
103
|
exports.default = useScrollTo;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Key } from '@v-c/util/dist/type';
|
|
2
2
|
import { Ref } from 'vue';
|
|
3
|
-
import { GetKey } from '../interface
|
|
4
|
-
import { default as CacheMap } from '../utils/CacheMap
|
|
3
|
+
import { GetKey } from '../interface';
|
|
4
|
+
import { default as CacheMap } from '../utils/CacheMap';
|
|
5
5
|
export type ScrollAlign = 'top' | 'bottom' | 'auto';
|
|
6
6
|
export interface ScrollPos {
|
|
7
7
|
left?: number;
|
|
@@ -16,4 +16,4 @@ export type ScrollTarget = {
|
|
|
16
16
|
align?: ScrollAlign;
|
|
17
17
|
offset?: number;
|
|
18
18
|
};
|
|
19
|
-
export default function useScrollTo(containerRef: Ref<HTMLDivElement>, data: Ref<any[]>, heights: CacheMap, itemHeight: Ref<number>, getKey: GetKey<any>, collectHeight: () => void, syncScrollTop: (newTop: number) => void, triggerFlash: () => void): (arg: number | ScrollTarget) => void;
|
|
19
|
+
export default function useScrollTo(containerRef: Ref<HTMLDivElement>, data: Ref<any[]>, heights: CacheMap, itemHeight: Ref<number>, getKey: GetKey<any>, collectHeight: () => void, syncScrollTop: (newTop: number) => void, triggerFlash: () => void): [(arg: number | ScrollTarget) => void, () => number];
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { shallowRef, watch } from "vue";
|
|
2
2
|
import { warning } from "@v-c/util";
|
|
3
|
-
import raf from "@v-c/util/dist/raf";
|
|
4
3
|
var MAX_TIMES = 10;
|
|
5
4
|
function useScrollTo(containerRef, data, heights, itemHeight, getKey, collectHeight, syncScrollTop, triggerFlash) {
|
|
6
|
-
const scrollRef = shallowRef();
|
|
7
5
|
const syncState = shallowRef(null);
|
|
8
|
-
|
|
6
|
+
const getTotalHeight = () => {
|
|
7
|
+
let totalHeight = 0;
|
|
8
|
+
for (let i = 0; i < data.value.length; i += 1) {
|
|
9
|
+
const key = getKey(data.value[i]);
|
|
10
|
+
const cacheHeight = heights.get(key);
|
|
11
|
+
totalHeight += cacheHeight === void 0 ? itemHeight.value : cacheHeight;
|
|
12
|
+
}
|
|
13
|
+
return totalHeight;
|
|
14
|
+
};
|
|
15
|
+
watch(syncState, () => {
|
|
9
16
|
if (syncState.value && syncState.value.times < MAX_TIMES) {
|
|
10
17
|
if (!containerRef.value) {
|
|
11
18
|
syncState.value = { ...syncState.value };
|
|
@@ -69,12 +76,11 @@ function useScrollTo(containerRef, data, heights, itemHeight, getKey, collectHei
|
|
|
69
76
|
immediate: true,
|
|
70
77
|
flush: "post"
|
|
71
78
|
});
|
|
72
|
-
|
|
79
|
+
const scrollTo = (arg) => {
|
|
73
80
|
if (arg === null || arg === void 0) {
|
|
74
81
|
triggerFlash();
|
|
75
82
|
return;
|
|
76
83
|
}
|
|
77
|
-
raf.cancel(scrollRef.value);
|
|
78
84
|
if (typeof arg === "number") syncScrollTop(arg);
|
|
79
85
|
else if (arg && typeof arg === "object") {
|
|
80
86
|
let index;
|
|
@@ -90,5 +96,6 @@ function useScrollTo(containerRef, data, heights, itemHeight, getKey, collectHei
|
|
|
90
96
|
};
|
|
91
97
|
}
|
|
92
98
|
};
|
|
99
|
+
return [scrollTo, getTotalHeight];
|
|
93
100
|
}
|
|
94
101
|
export { useScrollTo as default };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function getIndexByStartLoc(min, max, start, index) {
|
|
2
|
+
const beforeCount = start - min;
|
|
3
|
+
const afterCount = max - start;
|
|
4
|
+
if (index <= Math.min(beforeCount, afterCount) * 2) {
|
|
5
|
+
const stepIndex = Math.floor(index / 2);
|
|
6
|
+
if (index % 2) return start + stepIndex + 1;
|
|
7
|
+
return start - stepIndex;
|
|
8
|
+
}
|
|
9
|
+
if (beforeCount > afterCount) return start - (index - afterCount);
|
|
10
|
+
return start + (index - beforeCount);
|
|
11
|
+
}
|
|
12
|
+
function findListDiffIndex(originList, targetList, getKey) {
|
|
13
|
+
const originLen = originList.length;
|
|
14
|
+
const targetLen = targetList.length;
|
|
15
|
+
let shortList;
|
|
16
|
+
let longList;
|
|
17
|
+
if (originLen === 0 && targetLen === 0) return null;
|
|
18
|
+
if (originLen < targetLen) {
|
|
19
|
+
shortList = originList;
|
|
20
|
+
longList = targetList;
|
|
21
|
+
} else {
|
|
22
|
+
shortList = targetList;
|
|
23
|
+
longList = originList;
|
|
24
|
+
}
|
|
25
|
+
const notExistKey = { __EMPTY_ITEM__: true };
|
|
26
|
+
function getItemKey(item) {
|
|
27
|
+
if (item !== void 0) return getKey(item);
|
|
28
|
+
return notExistKey;
|
|
29
|
+
}
|
|
30
|
+
let diffIndex = null;
|
|
31
|
+
let multiple = Math.abs(originLen - targetLen) !== 1;
|
|
32
|
+
for (let i = 0; i < longList.length; i += 1) {
|
|
33
|
+
const shortKey = getItemKey(shortList[i]);
|
|
34
|
+
if (shortKey !== getItemKey(longList[i])) {
|
|
35
|
+
diffIndex = i;
|
|
36
|
+
multiple = multiple || shortKey !== getItemKey(longList[i + 1]);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return diffIndex === null ? null : {
|
|
41
|
+
index: diffIndex,
|
|
42
|
+
multiple
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
exports.findListDiffIndex = findListDiffIndex;
|
|
46
|
+
exports.getIndexByStartLoc = getIndexByStartLoc;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Key } from '@v-c/util/dist/type';
|
|
2
|
+
/**
|
|
3
|
+
* Get index with specific start index one by one. e.g.
|
|
4
|
+
* min: 3, max: 9, start: 6
|
|
5
|
+
*
|
|
6
|
+
* Return index is:
|
|
7
|
+
* [0]: 6
|
|
8
|
+
* [1]: 7
|
|
9
|
+
* [2]: 5
|
|
10
|
+
* [3]: 8
|
|
11
|
+
* [4]: 4
|
|
12
|
+
* [5]: 9
|
|
13
|
+
* [6]: 3
|
|
14
|
+
*/
|
|
15
|
+
export declare function getIndexByStartLoc(min: number, max: number, start: number, index: number): number;
|
|
16
|
+
/**
|
|
17
|
+
* We assume that 2 list has only 1 item diff and others keeping the order.
|
|
18
|
+
* So we can use dichotomy algorithm to find changed one.
|
|
19
|
+
*/
|
|
20
|
+
export declare function findListDiffIndex<T>(originList: T[], targetList: T[], getKey: (item: T) => Key): {
|
|
21
|
+
index: number;
|
|
22
|
+
multiple: boolean;
|
|
23
|
+
} | null;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
function getIndexByStartLoc(min, max, start, index) {
|
|
2
|
+
const beforeCount = start - min;
|
|
3
|
+
const afterCount = max - start;
|
|
4
|
+
if (index <= Math.min(beforeCount, afterCount) * 2) {
|
|
5
|
+
const stepIndex = Math.floor(index / 2);
|
|
6
|
+
if (index % 2) return start + stepIndex + 1;
|
|
7
|
+
return start - stepIndex;
|
|
8
|
+
}
|
|
9
|
+
if (beforeCount > afterCount) return start - (index - afterCount);
|
|
10
|
+
return start + (index - beforeCount);
|
|
11
|
+
}
|
|
12
|
+
function findListDiffIndex(originList, targetList, getKey) {
|
|
13
|
+
const originLen = originList.length;
|
|
14
|
+
const targetLen = targetList.length;
|
|
15
|
+
let shortList;
|
|
16
|
+
let longList;
|
|
17
|
+
if (originLen === 0 && targetLen === 0) return null;
|
|
18
|
+
if (originLen < targetLen) {
|
|
19
|
+
shortList = originList;
|
|
20
|
+
longList = targetList;
|
|
21
|
+
} else {
|
|
22
|
+
shortList = targetList;
|
|
23
|
+
longList = originList;
|
|
24
|
+
}
|
|
25
|
+
const notExistKey = { __EMPTY_ITEM__: true };
|
|
26
|
+
function getItemKey(item) {
|
|
27
|
+
if (item !== void 0) return getKey(item);
|
|
28
|
+
return notExistKey;
|
|
29
|
+
}
|
|
30
|
+
let diffIndex = null;
|
|
31
|
+
let multiple = Math.abs(originLen - targetLen) !== 1;
|
|
32
|
+
for (let i = 0; i < longList.length; i += 1) {
|
|
33
|
+
const shortKey = getItemKey(shortList[i]);
|
|
34
|
+
if (shortKey !== getItemKey(longList[i])) {
|
|
35
|
+
diffIndex = i;
|
|
36
|
+
multiple = multiple || shortKey !== getItemKey(longList[i + 1]);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return diffIndex === null ? null : {
|
|
41
|
+
index: diffIndex,
|
|
42
|
+
multiple
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export { findListDiffIndex, getIndexByStartLoc };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@v-c/virtual-list",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.3",
|
|
5
5
|
"description": "Vue Virtual List Component",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"vue": "^3.0.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@v-c/resize-observer": "^1.0.
|
|
34
|
+
"@v-c/resize-observer": "^1.0.1",
|
|
35
35
|
"@v-c/util": "^1.0.2"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|