Skip to content

⬅️ Back to Table of Contents

📄 index.ts

📊 Analysis Summary

Metric Count
🔧 Functions 15
📦 Imports 10
📊 Variables & Constants 11
🟢 Vue Composition API 6
📐 Interfaces 8
📑 Type Aliases 7

📚 Table of Contents

🛠️ File Location:

📂 packages/core/useVirtualList/index.ts

📦 Imports

Name Source
ComputedRef vue
MaybeRef vue
Ref vue
ShallowRef vue
StyleValue vue
computed vue
deepRef vue
shallowRef vue
watch vue
useElementSize ../useElementSize

Variables & Constants

Name Type Kind Value Exported
sum number let/var 0
capacity number let/var 0
sum number let/var 0
offset number let/var 0
element any const containerRef.value
from number const offset - overscan
to number const offset + viewCapacity + overscan
size number const index * itemSize
scrollToDictionaryForElementScrollKey { readonly horizontal: "scrollLeft"; readonly vertical: "scrollTop"; } const `{
horizontal: 'scrollLeft',
vertical: 'scrollTop',
} as const`
containerStyle StyleValue const { overflowX: 'auto' }
containerStyle StyleValue const { overflowY: 'auto' }

Vue Composition API

Name Type Reactive Variables Composables
watch watch none none
computed computed none none
computed computed none none
computed computed none none
computed computed none none
computed computed none none

Functions

useVirtualList(list: MaybeRef<readonly T[]>, options: UseVirtualListOptions): UseVirtualListReturn<T>

Code
export function useVirtualList<T = any>(list: MaybeRef<readonly T[]>, options: UseVirtualListOptions): UseVirtualListReturn<T> {
  const { containerStyle, wrapperProps, scrollTo, calculateRange, currentList, containerRef } = 'itemHeight' in options
    ? useVerticalVirtualList(options, list)
    : useHorizontalVirtualList(options, list)

  return {
    list: currentList,
    scrollTo,
    containerProps: {
      ref: containerRef,
      onScroll: () => {
        calculateRange()
      },
      style: containerStyle,
    },
    wrapperProps,
  }
}
  • JSDoc:

    /**
     * Please consider using [`vue-virtual-scroller`](https://github.com/Akryum/vue-virtual-scroller) if you are looking for more features.
     */
    

  • Parameters:

  • list: MaybeRef<readonly T[]>
  • options: UseVirtualListOptions
  • Return Type: UseVirtualListReturn<T>
  • Calls:
  • useVerticalVirtualList
  • useHorizontalVirtualList
  • calculateRange

onScroll(): void

Code
() => {
        calculateRange()
      }
  • Return Type: void
  • Calls:
  • calculateRange

onScroll(): void

Code
() => {
        calculateRange()
      }
  • Return Type: void
  • Calls:
  • calculateRange

onScroll(): void

Code
() => {
        calculateRange()
      }
  • Return Type: void
  • Calls:
  • calculateRange

onScroll(): void

Code
() => {
        calculateRange()
      }
  • Return Type: void
  • Calls:
  • calculateRange

useVirtualListResources(list: MaybeRef<readonly T[]>): UseVirtualListResources<T>

Code
function useVirtualListResources<T>(list: MaybeRef<readonly T[]>): UseVirtualListResources<T> {
  const containerRef = shallowRef<HTMLElement | null>(null)
  const size = useElementSize(containerRef)

  const currentList: Ref<UseVirtualListItem<T>[]> = deepRef([])
  const source = shallowRef(list)

  const state: Ref<{ start: number, end: number }> = deepRef({ start: 0, end: 10 })

  return { state, source, currentList, size, containerRef }
}
  • Parameters:
  • list: MaybeRef<readonly T[]>
  • Return Type: UseVirtualListResources<T>
  • Calls:
  • shallowRef (from vue)
  • useElementSize (from ../useElementSize)
  • deepRef (from vue)

createGetViewCapacity(state: UseVirtualListResources<T>['state'], source: UseVirtualListResources<T>['source'], itemSize: UseVirtualListItemSize): (containerSize: number) => number

Code
function createGetViewCapacity<T>(state: UseVirtualListResources<T>['state'], source: UseVirtualListResources<T>['source'], itemSize: UseVirtualListItemSize) {
  return (containerSize: number) => {
    if (typeof itemSize === 'number')
      return Math.ceil(containerSize / itemSize)

    const { start = 0 } = state.value
    let sum = 0
    let capacity = 0
    for (let i = start; i < source.value.length; i++) {
      const size = itemSize(i)
      sum += size
      capacity = i
      if (sum > containerSize)
        break
    }
    return capacity - start
  }
}
  • Parameters:
  • state: UseVirtualListResources<T>['state']
  • source: UseVirtualListResources<T>['source']
  • itemSize: UseVirtualListItemSize
  • Return Type: (containerSize: number) => number
  • Calls:
  • Math.ceil
  • itemSize

createGetOffset(source: UseVirtualListResources<T>['source'], itemSize: UseVirtualListItemSize): (scrollDirection: number) => number

Code
function createGetOffset<T>(source: UseVirtualListResources<T>['source'], itemSize: UseVirtualListItemSize) {
  return (scrollDirection: number) => {
    if (typeof itemSize === 'number')
      return Math.floor(scrollDirection / itemSize) + 1

    let sum = 0
    let offset = 0

    for (let i = 0; i < source.value.length; i++) {
      const size = itemSize(i)
      sum += size
      if (sum >= scrollDirection) {
        offset = i
        break
      }
    }
    return offset + 1
  }
}
  • Parameters:
  • source: UseVirtualListResources<T>['source']
  • itemSize: UseVirtualListItemSize
  • Return Type: (scrollDirection: number) => number
  • Calls:
  • Math.floor
  • itemSize

createCalculateRange(type: 'horizontal' | 'vertical', overscan: number, getOffset: ReturnType<typeof createGetOffset>, getViewCapacity: ReturnType<typeof createGetViewCapacity>, { containerRef, state, currentList, source }: UseVirtualListResources<T>): () => void

Code
function createCalculateRange<T>(type: 'horizontal' | 'vertical', overscan: number, getOffset: ReturnType<typeof createGetOffset>, getViewCapacity: ReturnType<typeof createGetViewCapacity>, { containerRef, state, currentList, source }: UseVirtualListResources<T>) {
  return () => {
    const element = containerRef.value
    if (element) {
      const offset = getOffset(type === 'vertical' ? element.scrollTop : element.scrollLeft)
      const viewCapacity = getViewCapacity(type === 'vertical' ? element.clientHeight : element.clientWidth)

      const from = offset - overscan
      const to = offset + viewCapacity + overscan
      state.value = {
        start: from < 0 ? 0 : from,
        end: to > source.value.length
          ? source.value.length
          : to,
      }
      currentList.value = source.value
        .slice(state.value.start, state.value.end)
        .map((ele, index) => ({
          data: ele,
          index: index + state.value.start,
        }))
    }
  }
}
  • Parameters:
  • type: 'horizontal' | 'vertical'
  • overscan: number
  • getOffset: ReturnType<typeof createGetOffset>
  • getViewCapacity: ReturnType<typeof createGetViewCapacity>
  • { containerRef, state, currentList, source }: UseVirtualListResources<T>
  • Return Type: () => void
  • Calls:
  • getOffset
  • getViewCapacity
  • source.value .slice(state.value.start, state.value.end) .map

createGetDistance(itemSize: UseVirtualListItemSize, source: UseVirtualListResources<T>['source']): (index: number) => any

Code
function createGetDistance<T>(itemSize: UseVirtualListItemSize, source: UseVirtualListResources<T>['source']) {
  return (index: number) => {
    if (typeof itemSize === 'number') {
      const size = index * itemSize
      return size
    }

    const size = source.value
      .slice(0, index)
      .reduce((sum, _, i) => sum + itemSize(i), 0)

    return size
  }
}
  • Parameters:
  • itemSize: UseVirtualListItemSize
  • source: UseVirtualListResources<T>['source']
  • Return Type: (index: number) => any
  • Calls:
  • source.value .slice(0, index) .reduce
  • itemSize

useWatchForSizes(size: UseVirtualElementSizes, list: MaybeRef<readonly T[]>, containerRef: Ref<HTMLElement | null>, calculateRange: () => void): void

Code
function useWatchForSizes<T>(size: UseVirtualElementSizes, list: MaybeRef<readonly T[]>, containerRef: Ref<HTMLElement | null>, calculateRange: () => void) {
  watch([size.width, size.height, list, containerRef], () => {
    calculateRange()
  })
}
  • Parameters:
  • size: UseVirtualElementSizes
  • list: MaybeRef<readonly T[]>
  • containerRef: Ref<HTMLElement | null>
  • calculateRange: () => void
  • Return Type: void
  • Calls:
  • watch (from vue)
  • calculateRange

createComputedTotalSize(itemSize: UseVirtualListItemSize, source: UseVirtualListResources<T>['source']): any

Code
function createComputedTotalSize<T>(itemSize: UseVirtualListItemSize, source: UseVirtualListResources<T>['source']) {
  return computed(() => {
    if (typeof itemSize === 'number')
      return source.value.length * itemSize

    return source.value.reduce((sum, _, index) => sum + itemSize(index), 0)
  })
}
  • Parameters:
  • itemSize: UseVirtualListItemSize
  • source: UseVirtualListResources<T>['source']
  • Return Type: any
  • Calls:
  • computed (from vue)
  • source.value.reduce
  • itemSize

createScrollTo(type: 'horizontal' | 'vertical', calculateRange: () => void, getDistance: ReturnType<typeof createGetDistance>, containerRef: UseVirtualListResources<T>['containerRef']): (index: number) => void

Code
function createScrollTo<T>(type: 'horizontal' | 'vertical', calculateRange: () => void, getDistance: ReturnType<typeof createGetDistance>, containerRef: UseVirtualListResources<T>['containerRef']) {
  return (index: number) => {
    if (containerRef.value) {
      containerRef.value[scrollToDictionaryForElementScrollKey[type]] = getDistance(index)
      calculateRange()
    }
  }
}
  • Parameters:
  • type: 'horizontal' | 'vertical'
  • calculateRange: () => void
  • getDistance: ReturnType<typeof createGetDistance>
  • containerRef: UseVirtualListResources<T>['containerRef']
  • Return Type: (index: number) => void
  • Calls:
  • getDistance
  • calculateRange

useHorizontalVirtualList(options: UseHorizontalVirtualListOptions, list: MaybeRef<readonly T[]>): { scrollTo: (index: number) => void; calculateRange: () => void; wrapperProps: any; containerStyle: StyleValue; currentList: Ref<UseVirtualListArray<T>>; containerRef: Ref<HTMLElement>; }

Code
function useHorizontalVirtualList<T>(options: UseHorizontalVirtualListOptions, list: MaybeRef<readonly T[]>) {
  const resources = useVirtualListResources(list)
  const { state, source, currentList, size, containerRef } = resources
  const containerStyle: StyleValue = { overflowX: 'auto' }

  const { itemWidth, overscan = 5 } = options

  const getViewCapacity = createGetViewCapacity(state, source, itemWidth)

  const getOffset = createGetOffset(source, itemWidth)

  const calculateRange = createCalculateRange('horizontal', overscan, getOffset, getViewCapacity, resources)

  const getDistanceLeft = createGetDistance(itemWidth, source)

  const offsetLeft = computed(() => getDistanceLeft(state.value.start))

  const totalWidth = createComputedTotalSize(itemWidth, source)

  useWatchForSizes(size, list, containerRef, calculateRange)

  const scrollTo = createScrollTo('horizontal', calculateRange, getDistanceLeft, containerRef)

  const wrapperProps = computed(() => {
    return {
      style: {
        height: '100%',
        width: `${totalWidth.value - offsetLeft.value}px`,
        marginLeft: `${offsetLeft.value}px`,
        display: 'flex',
      },
    }
  })

  return {
    scrollTo,
    calculateRange,
    wrapperProps,
    containerStyle,
    currentList,
    containerRef,
  }
}
  • Parameters:
  • options: UseHorizontalVirtualListOptions
  • list: MaybeRef<readonly T[]>
  • Return Type: { scrollTo: (index: number) => void; calculateRange: () => void; wrapperProps: any; containerStyle: StyleValue; currentList: Ref<UseVirtualListArray<T>>; containerRef: Ref<HTMLElement>; }
  • Calls:
  • useVirtualListResources
  • createGetViewCapacity
  • createGetOffset
  • createCalculateRange
  • createGetDistance
  • computed (from vue)
  • getDistanceLeft
  • createComputedTotalSize
  • useWatchForSizes
  • createScrollTo

useVerticalVirtualList(options: UseVerticalVirtualListOptions, list: MaybeRef<readonly T[]>): { calculateRange: () => void; scrollTo: (index: number) => void; containerStyle: StyleValue; wrapperProps: any; currentList: Ref<UseVirtualListArray<T>>; containerRef: Ref<HTMLElement>; }

Code
function useVerticalVirtualList<T>(options: UseVerticalVirtualListOptions, list: MaybeRef<readonly T[]>) {
  const resources = useVirtualListResources(list)

  const { state, source, currentList, size, containerRef } = resources

  const containerStyle: StyleValue = { overflowY: 'auto' }

  const { itemHeight, overscan = 5 } = options

  const getViewCapacity = createGetViewCapacity(state, source, itemHeight)

  const getOffset = createGetOffset(source, itemHeight)

  const calculateRange = createCalculateRange('vertical', overscan, getOffset, getViewCapacity, resources)

  const getDistanceTop = createGetDistance(itemHeight, source)

  const offsetTop = computed(() => getDistanceTop(state.value.start))

  const totalHeight = createComputedTotalSize(itemHeight, source)

  useWatchForSizes(size, list, containerRef, calculateRange)

  const scrollTo = createScrollTo('vertical', calculateRange, getDistanceTop, containerRef)

  const wrapperProps = computed(() => {
    return {
      style: {
        width: '100%',
        height: `${totalHeight.value - offsetTop.value}px`,
        marginTop: `${offsetTop.value}px`,
      },
    }
  })

  return {
    calculateRange,
    scrollTo,
    containerStyle,
    wrapperProps,
    currentList,
    containerRef,
  }
}
  • Parameters:
  • options: UseVerticalVirtualListOptions
  • list: MaybeRef<readonly T[]>
  • Return Type: { calculateRange: () => void; scrollTo: (index: number) => void; containerStyle: StyleValue; wrapperProps: any; currentList: Ref<UseVirtualListArray<T>>; containerRef: Ref<HTMLElement>; }
  • Calls:
  • useVirtualListResources
  • createGetViewCapacity
  • createGetOffset
  • createCalculateRange
  • createGetDistance
  • computed (from vue)
  • getDistanceTop
  • createComputedTotalSize
  • useWatchForSizes
  • createScrollTo

Interfaces

UseHorizontalVirtualListOptions

Interface Code
export interface UseHorizontalVirtualListOptions extends UseVirtualListOptionsBase {

  /**
   * item width, accept a pixel value or a function that returns the width
   *
   * @default 0
   */
  itemWidth: UseVirtualListItemSize

}

Properties

Name Type Optional Description
itemWidth UseVirtualListItemSize

UseVerticalVirtualListOptions

Interface Code
export interface UseVerticalVirtualListOptions extends UseVirtualListOptionsBase {
  /**
   * item height, accept a pixel value or a function that returns the height
   *
   * @default 0
   */
  itemHeight: UseVirtualListItemSize
}

Properties

Name Type Optional Description
itemHeight UseVirtualListItemSize

UseVirtualListOptionsBase

Interface Code
export interface UseVirtualListOptionsBase {
  /**
   * the extra buffer items outside of the view area
   *
   * @default 5
   */
  overscan?: number
}

Properties

Name Type Optional Description
overscan number

UseVirtualListItem<T>

Interface Code
export interface UseVirtualListItem<T> {
  data: T
  index: number
}

Properties

Name Type Optional Description
data T
index number

UseVirtualListReturn<T>

Interface Code
export interface UseVirtualListReturn<T> {
  list: Ref<UseVirtualListItem<T>[]>
  scrollTo: (index: number) => void

  containerProps: {
    ref: Ref<HTMLElement | null>
    onScroll: () => void
    style: StyleValue
  }
  wrapperProps: ComputedRef<{
    style: {
      width: string
      height: string
      marginTop: string
    } | {
      width: string
      height: string
      marginLeft: string
      display: string
    }
  }>
}

Properties

Name Type Optional Description
list Ref<UseVirtualListItem<T>[]>
scrollTo (index: number) => void
containerProps `{
ref: Ref<HTMLElement null>
onScroll: () => void
style: StyleValue
}`
wrapperProps `ComputedRef<{
style: {
width: string
height: string
marginTop: string
} {
width: string
height: string
marginLeft: string
display: string
}
}>`

UseVirtualElementSizes

Interface Code
interface UseVirtualElementSizes {
  width: Ref<number>
  height: Ref<number>
}

Properties

Name Type Optional Description
width Ref<number>
height Ref<number>

UseVirtualListState

Interface Code
interface UseVirtualListState { start: number, end: number }

Properties

Name Type Optional Description
start number
end number

UseVirtualListResources<T>

Interface Code
interface UseVirtualListResources<T> {
  state: RefState
  source: UseVirtualListSource<T>
  currentList: UseVirtualListRefArray<T>
  size: UseVirtualElementSizes
  containerRef: UseVirtualListContainerRef
}

Properties

Name Type Optional Description
state RefState
source UseVirtualListSource<T>
currentList UseVirtualListRefArray<T>
size UseVirtualElementSizes
containerRef UseVirtualListContainerRef

Type Aliases

UseVirtualListItemSize

type UseVirtualListItemSize = number | ((index: number) => number);

UseVirtualListOptions

type UseVirtualListOptions = UseHorizontalVirtualListOptions | UseVerticalVirtualListOptions;

UseVirtualListContainerRef

type UseVirtualListContainerRef = Ref<HTMLElement | null>;

UseVirtualListArray<T>

type UseVirtualListArray<T> = UseVirtualListItem<T>[];

UseVirtualListRefArray<T>

type UseVirtualListRefArray<T> = Ref<UseVirtualListArray<T>>;

UseVirtualListSource<T>

type UseVirtualListSource<T> = Ref<readonly T[]> | ShallowRef<readonly T[]>;

RefState

type RefState = Ref<UseVirtualListState>;