@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 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 require_Item = require("./Item.cjs");
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.computed)(() => props.data || EMPTY_DATA);
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, () => contentScrollWidth.value], () => {
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), syncScrollTop, delayHideScrollBar);
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
- }, _isSlot(_slot = renderChildren()) ? _slot : { default: () => [_slot] })] })] }),
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 Item_default from "./Item.js";
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, isVNode, mergeProps, ref, shallowRef, toRaw, toRef, watch } from "vue";
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 = computed(() => props.data || EMPTY_DATA);
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, () => contentScrollWidth.value], () => {
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), syncScrollTop, delayHideScrollBar);
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
- }, _isSlot(_slot = renderChildren()) ? _slot : { default: () => [_slot] })] })] }),
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 prevDataRef = (0, vue.ref)([]);
6
- const diffItem = (0, vue.ref)();
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 prevData = prevDataRef.value;
9
- if (newData !== prevData) {
10
- diffItem.value = newData.find((item) => {
11
- const key = getKey(item);
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 { ref, watch } from "vue";
2
- function useDiffItem(data, getKey) {
3
- const prevDataRef = ref([]);
4
- const diffItem = ref();
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 prevData = prevDataRef.value;
7
- if (newData !== prevData) {
8
- diffItem.value = newData.find((item) => {
9
- const key = getKey(item);
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
- (0, vue.watch)([syncState, containerRef], () => {
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
- return (arg) => {
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.ts';
4
- import { default as CacheMap } from '../utils/CacheMap.ts';
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
- watch([syncState, containerRef], () => {
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
- return (arg) => {
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.1",
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.0",
34
+ "@v-c/resize-observer": "^1.0.1",
35
35
  "@v-c/util": "^1.0.2"
36
36
  },
37
37
  "scripts": {