@v-c/virtual-list 1.0.1 → 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 +25 -33
- package/dist/List.js +26 -34
- 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,7 @@
|
|
|
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
5
|
const require_useDiffItem = require("./hooks/useDiffItem.cjs");
|
|
6
6
|
const require_useFrameWheel = require("./hooks/useFrameWheel.cjs");
|
|
7
7
|
const require_useGetSize = require("./hooks/useGetSize.cjs");
|
|
@@ -15,9 +15,6 @@ let vue = require("vue");
|
|
|
15
15
|
let __v_c_resize_observer = require("@v-c/resize-observer");
|
|
16
16
|
__v_c_resize_observer = require_rolldown_runtime.__toESM(__v_c_resize_observer);
|
|
17
17
|
let __v_c_util_dist_props_util = require("@v-c/util/dist/props-util");
|
|
18
|
-
function _isSlot(s) {
|
|
19
|
-
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !(0, vue.isVNode)(s);
|
|
20
|
-
}
|
|
21
18
|
var EMPTY_DATA = [];
|
|
22
19
|
var ScrollStyle = {
|
|
23
20
|
overflowY: "auto",
|
|
@@ -77,7 +74,10 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
77
74
|
return item?.[_itemKey];
|
|
78
75
|
};
|
|
79
76
|
const [setInstanceRef, collectHeight, heights, heightUpdatedMark] = require_useHeights.default(getKey, void 0, void 0);
|
|
80
|
-
const mergedData = (0, vue.
|
|
77
|
+
const mergedData = (0, vue.shallowRef)(props?.data || EMPTY_DATA);
|
|
78
|
+
(0, vue.watch)(() => props.data, () => {
|
|
79
|
+
mergedData.value = props?.data || EMPTY_DATA;
|
|
80
|
+
});
|
|
81
81
|
const useVirtual = (0, vue.computed)(() => !!(props.virtual !== false && props.height && props.itemHeight));
|
|
82
82
|
const containerHeight = (0, vue.computed)(() => Object.values(heights.maps).reduce((total, curr) => total + curr, 0));
|
|
83
83
|
const inVirtual = (0, vue.computed)(() => {
|
|
@@ -108,7 +108,6 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
108
108
|
if (componentRef.value) componentRef.value.scrollTop = alignedTop;
|
|
109
109
|
offsetTop.value = alignedTop;
|
|
110
110
|
}
|
|
111
|
-
require_useDiffItem.default(mergedData, getKey);
|
|
112
111
|
(0, vue.watch)([
|
|
113
112
|
inVirtual,
|
|
114
113
|
useVirtual,
|
|
@@ -124,7 +123,6 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
124
123
|
fillerOffset.value = void 0;
|
|
125
124
|
return;
|
|
126
125
|
}
|
|
127
|
-
const { itemHeight: itemHeight$1, height } = props;
|
|
128
126
|
if (!inVirtual.value) {
|
|
129
127
|
scrollHeight.value = fillerInnerRef.value?.offsetHeight || 0;
|
|
130
128
|
start.value = 0;
|
|
@@ -132,6 +130,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
132
130
|
fillerOffset.value = void 0;
|
|
133
131
|
return;
|
|
134
132
|
}
|
|
133
|
+
const { itemHeight: itemHeight$1, height } = props;
|
|
135
134
|
let itemTop = 0;
|
|
136
135
|
let startIndex;
|
|
137
136
|
let startOffset;
|
|
@@ -149,6 +148,10 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
149
148
|
}
|
|
150
149
|
if (currentItemBottom > offsetTop.value + height && endIndex === void 0) endIndex = i;
|
|
151
150
|
itemTop = currentItemBottom;
|
|
151
|
+
if (startIndex !== void 0 && endIndex !== void 0) {
|
|
152
|
+
itemTop = currentItemBottom + (dataLen - 1 - i) * itemHeight$1;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
152
155
|
}
|
|
153
156
|
if (startIndex === void 0) {
|
|
154
157
|
startIndex = 0;
|
|
@@ -253,6 +256,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
253
256
|
const onScrollbarStopMove = () => {
|
|
254
257
|
scrollMoving.value = false;
|
|
255
258
|
};
|
|
259
|
+
require_useDiffItem.default(mergedData, getKey);
|
|
256
260
|
(0, vue.watch)([
|
|
257
261
|
() => props.height,
|
|
258
262
|
scrollHeight,
|
|
@@ -261,7 +265,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
261
265
|
], () => {
|
|
262
266
|
if (inVirtual.value && props.height && scrollHeight.value) verticalScrollBarSpinSize.value = require_scrollbarUtil.getSpinSize(size.value.height, scrollHeight.value);
|
|
263
267
|
}, { immediate: true });
|
|
264
|
-
(0, vue.watch)([() => size.value.width,
|
|
268
|
+
(0, vue.watch)([() => size.value.width, contentScrollWidth], () => {
|
|
265
269
|
if (inVirtual.value && contentScrollWidth.value) horizontalScrollBarSpinSize.value = require_scrollbarUtil.getSpinSize(size.value.width, contentScrollWidth.value);
|
|
266
270
|
}, { immediate: true });
|
|
267
271
|
(0, vue.watch)(() => props.scrollWidth, (val) => {
|
|
@@ -274,7 +278,13 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
274
278
|
props.onScroll?.(e);
|
|
275
279
|
triggerScroll();
|
|
276
280
|
}
|
|
277
|
-
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);
|
|
278
288
|
expose({
|
|
279
289
|
nativeElement: containerRef,
|
|
280
290
|
getScrollInfo: getVirtualScrollInfo,
|
|
@@ -299,30 +309,12 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
299
309
|
}
|
|
300
310
|
});
|
|
301
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 });
|
|
302
317
|
return () => {
|
|
303
|
-
let _slot;
|
|
304
|
-
const renderChildren = () => {
|
|
305
|
-
const children = [];
|
|
306
|
-
const data = mergedData.value;
|
|
307
|
-
const defaultSlot = slots.default;
|
|
308
|
-
if (!defaultSlot) return children;
|
|
309
|
-
for (let i = start.value; i <= end.value; i += 1) {
|
|
310
|
-
const item = data[i];
|
|
311
|
-
const key = getKey(item);
|
|
312
|
-
const nodes = defaultSlot({
|
|
313
|
-
item,
|
|
314
|
-
index: i,
|
|
315
|
-
style: {},
|
|
316
|
-
offsetX: offsetLeft.value
|
|
317
|
-
});
|
|
318
|
-
const node = Array.isArray(nodes) ? nodes[0] : nodes;
|
|
319
|
-
if (node) children.push((0, vue.createVNode)(require_Item.default, {
|
|
320
|
-
"key": key,
|
|
321
|
-
"setRef": (ele) => setInstanceRef(item, ele)
|
|
322
|
-
}, _isSlot(node) ? node : { default: () => [node] }));
|
|
323
|
-
}
|
|
324
|
-
return children;
|
|
325
|
-
};
|
|
326
318
|
const componentStyle = {};
|
|
327
319
|
if (props.height) {
|
|
328
320
|
componentStyle[props.fullHeight ? "height" : "maxHeight"] = `${props.height}px`;
|
|
@@ -373,7 +365,7 @@ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
373
365
|
"innerProps": props.innerProps,
|
|
374
366
|
"rtl": isRTL.value,
|
|
375
367
|
"extra": extraContent
|
|
376
|
-
},
|
|
368
|
+
}, { default: () => [listChildren.value] })] })] }),
|
|
377
369
|
inVirtual.value && scrollHeight.value > (props.height || 0) && (0, vue.createVNode)(require_ScrollBar.default, {
|
|
378
370
|
"ref": verticalScrollBarRef,
|
|
379
371
|
"prefixCls": props.prefixCls,
|
package/dist/List.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Filler_default from "./Filler.js";
|
|
2
|
-
import
|
|
2
|
+
import useChildren from "./hooks/useChildren.js";
|
|
3
3
|
import useDiffItem from "./hooks/useDiffItem.js";
|
|
4
4
|
import useFrameWheel from "./hooks/useFrameWheel.js";
|
|
5
5
|
import { useGetSize } from "./hooks/useGetSize.js";
|
|
@@ -9,12 +9,9 @@ import useScrollDrag from "./hooks/useScrollDrag.js";
|
|
|
9
9
|
import useScrollTo from "./hooks/useScrollTo.js";
|
|
10
10
|
import ScrollBar_default from "./ScrollBar.js";
|
|
11
11
|
import { getSpinSize } from "./utils/scrollbarUtil.js";
|
|
12
|
-
import { computed, createVNode, defineComponent,
|
|
12
|
+
import { computed, createVNode, defineComponent, mergeProps, ref, shallowRef, toRaw, toRef, watch } from "vue";
|
|
13
13
|
import ResizeObserver from "@v-c/resize-observer";
|
|
14
14
|
import { pureAttrs } from "@v-c/util/dist/props-util";
|
|
15
|
-
function _isSlot(s) {
|
|
16
|
-
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
17
|
-
}
|
|
18
15
|
var EMPTY_DATA = [];
|
|
19
16
|
var ScrollStyle = {
|
|
20
17
|
overflowY: "auto",
|
|
@@ -74,7 +71,10 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
74
71
|
return item?.[_itemKey];
|
|
75
72
|
};
|
|
76
73
|
const [setInstanceRef, collectHeight, heights, heightUpdatedMark] = useHeights(getKey, void 0, void 0);
|
|
77
|
-
const mergedData =
|
|
74
|
+
const mergedData = shallowRef(props?.data || EMPTY_DATA);
|
|
75
|
+
watch(() => props.data, () => {
|
|
76
|
+
mergedData.value = props?.data || EMPTY_DATA;
|
|
77
|
+
});
|
|
78
78
|
const useVirtual = computed(() => !!(props.virtual !== false && props.height && props.itemHeight));
|
|
79
79
|
const containerHeight = computed(() => Object.values(heights.maps).reduce((total, curr) => total + curr, 0));
|
|
80
80
|
const inVirtual = computed(() => {
|
|
@@ -105,7 +105,6 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
105
105
|
if (componentRef.value) componentRef.value.scrollTop = alignedTop;
|
|
106
106
|
offsetTop.value = alignedTop;
|
|
107
107
|
}
|
|
108
|
-
useDiffItem(mergedData, getKey);
|
|
109
108
|
watch([
|
|
110
109
|
inVirtual,
|
|
111
110
|
useVirtual,
|
|
@@ -121,7 +120,6 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
121
120
|
fillerOffset.value = void 0;
|
|
122
121
|
return;
|
|
123
122
|
}
|
|
124
|
-
const { itemHeight: itemHeight$1, height } = props;
|
|
125
123
|
if (!inVirtual.value) {
|
|
126
124
|
scrollHeight.value = fillerInnerRef.value?.offsetHeight || 0;
|
|
127
125
|
start.value = 0;
|
|
@@ -129,6 +127,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
129
127
|
fillerOffset.value = void 0;
|
|
130
128
|
return;
|
|
131
129
|
}
|
|
130
|
+
const { itemHeight: itemHeight$1, height } = props;
|
|
132
131
|
let itemTop = 0;
|
|
133
132
|
let startIndex;
|
|
134
133
|
let startOffset;
|
|
@@ -146,6 +145,10 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
146
145
|
}
|
|
147
146
|
if (currentItemBottom > offsetTop.value + height && endIndex === void 0) endIndex = i;
|
|
148
147
|
itemTop = currentItemBottom;
|
|
148
|
+
if (startIndex !== void 0 && endIndex !== void 0) {
|
|
149
|
+
itemTop = currentItemBottom + (dataLen - 1 - i) * itemHeight$1;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
149
152
|
}
|
|
150
153
|
if (startIndex === void 0) {
|
|
151
154
|
startIndex = 0;
|
|
@@ -250,6 +253,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
250
253
|
const onScrollbarStopMove = () => {
|
|
251
254
|
scrollMoving.value = false;
|
|
252
255
|
};
|
|
256
|
+
useDiffItem(mergedData, getKey);
|
|
253
257
|
watch([
|
|
254
258
|
() => props.height,
|
|
255
259
|
scrollHeight,
|
|
@@ -258,7 +262,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
258
262
|
], () => {
|
|
259
263
|
if (inVirtual.value && props.height && scrollHeight.value) verticalScrollBarSpinSize.value = getSpinSize(size.value.height, scrollHeight.value);
|
|
260
264
|
}, { immediate: true });
|
|
261
|
-
watch([() => size.value.width,
|
|
265
|
+
watch([() => size.value.width, contentScrollWidth], () => {
|
|
262
266
|
if (inVirtual.value && contentScrollWidth.value) horizontalScrollBarSpinSize.value = getSpinSize(size.value.width, contentScrollWidth.value);
|
|
263
267
|
}, { immediate: true });
|
|
264
268
|
watch(() => props.scrollWidth, (val) => {
|
|
@@ -271,7 +275,13 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
271
275
|
props.onScroll?.(e);
|
|
272
276
|
triggerScroll();
|
|
273
277
|
}
|
|
274
|
-
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);
|
|
275
285
|
expose({
|
|
276
286
|
nativeElement: containerRef,
|
|
277
287
|
getScrollInfo: getVirtualScrollInfo,
|
|
@@ -296,30 +306,12 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
296
306
|
}
|
|
297
307
|
});
|
|
298
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 });
|
|
299
314
|
return () => {
|
|
300
|
-
let _slot;
|
|
301
|
-
const renderChildren = () => {
|
|
302
|
-
const children = [];
|
|
303
|
-
const data = mergedData.value;
|
|
304
|
-
const defaultSlot = slots.default;
|
|
305
|
-
if (!defaultSlot) return children;
|
|
306
|
-
for (let i = start.value; i <= end.value; i += 1) {
|
|
307
|
-
const item = data[i];
|
|
308
|
-
const key = getKey(item);
|
|
309
|
-
const nodes = defaultSlot({
|
|
310
|
-
item,
|
|
311
|
-
index: i,
|
|
312
|
-
style: {},
|
|
313
|
-
offsetX: offsetLeft.value
|
|
314
|
-
});
|
|
315
|
-
const node = Array.isArray(nodes) ? nodes[0] : nodes;
|
|
316
|
-
if (node) children.push(createVNode(Item_default, {
|
|
317
|
-
"key": key,
|
|
318
|
-
"setRef": (ele) => setInstanceRef(item, ele)
|
|
319
|
-
}, _isSlot(node) ? node : { default: () => [node] }));
|
|
320
|
-
}
|
|
321
|
-
return children;
|
|
322
|
-
};
|
|
323
315
|
const componentStyle = {};
|
|
324
316
|
if (props.height) {
|
|
325
317
|
componentStyle[props.fullHeight ? "height" : "maxHeight"] = `${props.height}px`;
|
|
@@ -370,7 +362,7 @@ var List_default = /* @__PURE__ */ defineComponent({
|
|
|
370
362
|
"innerProps": props.innerProps,
|
|
371
363
|
"rtl": isRTL.value,
|
|
372
364
|
"extra": extraContent
|
|
373
|
-
},
|
|
365
|
+
}, { default: () => [listChildren.value] })] })] }),
|
|
374
366
|
inVirtual.value && scrollHeight.value > (props.height || 0) && createVNode(ScrollBar_default, {
|
|
375
367
|
"ref": verticalScrollBarRef,
|
|
376
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": {
|