|
1 | | -import { computed, onBeforeUnmount, onMounted, toRaw } from 'vue' |
2 | | -import throttle from 'lodash-es/throttle' |
| 1 | +import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue' |
| 2 | +import { useThrottleFn, debouncedWatch } from '@vueuse/core' |
| 3 | +import { renderLines } from './utils' |
3 | 4 |
|
4 | 5 | import type { ComputedRef, Ref } from 'vue' |
5 | | -import type { Meta, Lines, VirtualScroll } from './types' |
| 6 | +import type { Mode, Theme, Meta, Lines, VirtualScroll } from './types' |
6 | 7 |
|
7 | | -type UseVirtualScroll = (params: { |
8 | | - viewer: Ref<null|HTMLElement>; |
| 8 | +interface Props { |
| 9 | + mode: Mode; |
| 10 | + theme: Theme; |
| 11 | + language: string; |
| 12 | + prev: string; |
| 13 | + current: string; |
| 14 | + inputDelay: number; |
9 | 15 | virtualScroll: boolean|VirtualScroll; |
10 | | - meta: Ref<Array<Meta>>; |
11 | | - render: Ref<Array<Lines>>; |
12 | | -}) => { |
13 | | - minHeight: ComputedRef<null|number>; |
14 | | - scrollOptions: ComputedRef<null|VirtualScroll>; |
15 | | - setMeta: () => void; |
16 | 16 | } |
17 | 17 |
|
18 | | -export const useVirtualScroll: UseVirtualScroll = ({ viewer, virtualScroll, meta }) => { |
19 | | - const scrollOptions = computed(() => { |
20 | | - if (!virtualScroll) return null |
21 | | - return { |
22 | | - height: 500, |
23 | | - lineMinHeight: 24, |
24 | | - scrollDelay: 250, |
25 | | - ...(typeof virtualScroll === 'object' ? toRaw(virtualScroll) : {}) |
26 | | - } |
27 | | - }) |
| 18 | +export const useRender = (props: Props, viewer: Ref<null|HTMLElement>, scrollOptions: ComputedRef<false|VirtualScroll>) => { |
| 19 | + const render = ref<Array<Lines>>([]) |
| 20 | + const meta = ref<Array<Meta>>([]) |
| 21 | + const visible = computed(() => meta.value.filter(item => item.visible)) |
| 22 | + |
| 23 | + // debouncedWatch( |
| 24 | + // [() => props.mode, () => props.prev, () => props.current, () => props.inputDelay], |
| 25 | + // () => { console.log('changed!') }, |
| 26 | + // { debounce: props.inputDelay } |
| 27 | + // ) |
| 28 | + |
| 29 | + watch( |
| 30 | + [() => props.mode, () => props.prev, () => props.current], |
| 31 | + () => { |
| 32 | + const result = renderLines(props.mode, props.prev, props.current) |
| 33 | + render.value = result |
| 34 | + meta.value.splice(render.value.length) |
28 | 35 |
|
| 36 | + render.value.map((v, index: number) => { |
| 37 | + const item = meta.value[index] |
| 38 | + |
| 39 | + if (scrollOptions.value) { |
| 40 | + meta.value[index] = { |
| 41 | + index, |
| 42 | + visible: item?.visible || false, |
| 43 | + top: item?.top || undefined, |
| 44 | + height: item?.height || scrollOptions.value.lineMinHeight |
| 45 | + } |
| 46 | + } else { |
| 47 | + meta.value[index] = { |
| 48 | + index, |
| 49 | + visible: true |
| 50 | + } |
| 51 | + } |
| 52 | + }) |
| 53 | + }, |
| 54 | + { immediate: true } |
| 55 | + ) |
| 56 | + |
| 57 | + return { |
| 58 | + meta, |
| 59 | + render, |
| 60 | + visible |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +export const useVirtualScroll = (props: Props, viewer: Ref<null|HTMLElement>, scrollOptions: ComputedRef<false|VirtualScroll>, meta: Ref<Array<Meta>>) => { |
29 | 65 | const minHeight = computed(() => { |
30 | | - if (!scrollOptions.value) return null |
31 | | - return meta.value.reduce((acc, curr) => { |
| 66 | + if (!scrollOptions.value) return undefined |
| 67 | + const reduce = meta.value.reduce((acc, curr) => { |
32 | 68 | curr.top = acc |
33 | | - return acc + curr.height |
| 69 | + return acc + (curr.height as number) |
34 | 70 | }, 0) |
| 71 | + return reduce + 'px' |
35 | 72 | }) |
36 | 73 |
|
37 | 74 | const setMeta = () => { |
38 | | - console.log('setMeta') |
39 | 75 | if (!viewer.value || !scrollOptions.value) return |
40 | | - const start = viewer.value.scrollTop - scrollOptions.value.height * 1.5 |
41 | | - const end = viewer.value.scrollTop + scrollOptions.value.height + scrollOptions.value.height * 1.5 |
| 76 | + const scrollTop = viewer.value.scrollTop |
| 77 | + const height = scrollOptions.value.height |
| 78 | + const min = scrollTop - height * 1.5 |
| 79 | + const max = scrollTop + height + height * 1.5 |
42 | 80 |
|
43 | 81 | meta.value.reduce((acc, curr) => { |
44 | | - if (acc >= start && acc <= end) { |
| 82 | + if (acc >= min && acc <= max) { |
45 | 83 | curr.visible = true |
46 | 84 | } else { |
47 | 85 | curr.visible = false |
48 | 86 | } |
49 | 87 |
|
50 | 88 | curr.top = acc |
51 | | - return acc + curr.height |
| 89 | + return acc + (curr.height as number) |
52 | 90 | }, 0) |
53 | 91 | } |
54 | 92 |
|
55 | 93 | onMounted(() => { |
56 | 94 | if (!scrollOptions.value) return |
57 | | - viewer.value?.addEventListener('scroll', throttle(setMeta, scrollOptions.value.scrollDelay)) |
58 | | - setMeta() |
| 95 | + viewer.value?.addEventListener('scroll', useThrottleFn(setMeta, scrollOptions.value.scrollDelay)) |
| 96 | + |
| 97 | + // debouncedWatch( |
| 98 | + // [() => props.mode, () => props.prev, () => props.current, () => props.inputDelay], |
| 99 | + // () => { console.log('changed!') }, |
| 100 | + // { debounce: props.inputDelay } |
| 101 | + // ) |
| 102 | + |
| 103 | + watch( |
| 104 | + [() => props.mode, () => props.prev, () => props.current], |
| 105 | + () => nextTick(setMeta), |
| 106 | + { immediate: true } |
| 107 | + ) |
59 | 108 | }) |
60 | 109 |
|
61 | 110 | onBeforeUnmount(() => { |
62 | 111 | if (!scrollOptions.value) return |
63 | | - viewer.value?.removeEventListener('scroll', throttle(setMeta, scrollOptions.value.scrollDelay)) |
| 112 | + viewer.value?.removeEventListener('scroll', useThrottleFn(setMeta, scrollOptions.value.scrollDelay)) |
64 | 113 | }) |
65 | 114 |
|
66 | 115 | return { |
67 | | - minHeight, |
68 | | - scrollOptions, |
69 | | - setMeta |
| 116 | + minHeight |
70 | 117 | } |
71 | 118 | } |
0 commit comments