66 <div
77 ref="viewer"
88 class="vue-diff-viewer"
9- :style="{ height: viewerHeight ? viewerHeight + 'px' : undefined }"
9+ :style="{ height: scrollOptions ? scrollOptions.height + 'px' : undefined }"
1010 >
1111 <div
1212 class="vue-diff-viewer-inner"
13- :style="{ minHeight: innerMinHeight ? innerMinHeight + 'px' : undefined }"
13+ :style="{ minHeight: minHeight ? minHeight + 'px' : undefined }"
1414 >
1515 <Line
16+ v-for="(data, index) in visible"
1617 :key="index"
17- v-for="(data, index) in visibleData"
18- :index="index"
1918 :mode="mode"
2019 :language="language"
21- :data="data"
22- :virtualScroll="virtualScroll"
23- @set-line-height="setLineHeight"
20+ :meta="meta[data.index]"
21+ :render="render[data.index]"
22+ :virtualScroll="scrollOptions"
23+ @setLineHeight="setLineHeight"
2424 />
2525 </div>
2626 </div>
2727 </div>
2828</template>
2929
3030<script lang="ts">
31- import { defineComponent, PropType, ref, watch, onMounted, onBeforeUnmount, computed, readonly, toRaw } from 'vue'
32- import throttle from 'lodash-es/throttle'
33- import { renderLines, renderWords } from './utils'
31+ import {
32+ computed,
33+ defineComponent,
34+ onMounted,
35+ ref,
36+ watch
37+ } from 'vue'
38+ import debounce from 'lodash-es/debounce'
39+ import { useVirtualScroll } from './hooks'
40+ import { renderLines } from './utils'
3441import Line from './Line.vue'
3542
36- import type { Mode, Theme, Lines } from './utils'
37-
38- interface VirtualScroll {
39- height?: number;
40- lineMinHeight?: number;
41- }
42-
43- interface Data {
44- key: number;
45- render: Lines;
46- top?: number;
47- height?: number;
48- }
43+ import type { PropType } from 'vue'
44+ import type { Meta, VirtualScroll, Mode, Theme, Lines } from './types'
4945
5046export default defineComponent({
5147 components: {
@@ -72,101 +68,71 @@ export default defineComponent({
7268 type: String,
7369 default: ''
7470 },
71+ inputDelay: {
72+ type: Number,
73+ default: 0
74+ },
7575 virtualScroll: {
76- type: false || Object as PropType<VirtualScroll>,
76+ type: [Boolean, Object] as PropType<boolean| VirtualScroll>,
7777 default: false
7878 }
7979 },
8080 setup (props) {
8181 const viewer = ref<null|HTMLElement>(null)
82- const source = ref<Array<Data>>([])
83- const visibleData = ref<Array<Data>>([])
84- const heightList = ref<Array<number>>([])
85-
86- const viewerHeight = computed(() => {
87- if (!props.virtualScroll) return false
88- return props.virtualScroll.height || 500
89- })
90-
91- const innerMinHeight = computed(() => {
92- if (!props.virtualScroll) return false
93- return heightList.value.reduce((acc, curr) => acc + curr, 0)
82+ const meta = ref<Array<Meta>>([])
83+ const render = ref<Array<Lines>>([])
84+ const visible = computed(() => meta.value.filter(item => item.visible))
85+ const { minHeight, scrollOptions, setMeta } = useVirtualScroll({
86+ meta,
87+ viewer,
88+ virtualScroll: props.virtualScroll,
89+ render
9490 })
9591
96- const getVisibleData = () => {
97- if (!viewer.value || !viewerHeight.value) return []
98-
99- const result: Data[] = []
100- const start = viewer.value.scrollTop - viewerHeight.value
101- const end = viewer.value.scrollTop + viewerHeight.value * 2
102-
103- heightList.value.reduce((acc, curr, index: number) => {
104- if (acc >= start && acc <= end) {
105- result.push({
106- key: index,
107- render: source.value[index].render,
108- top: acc,
109- height: 24
110- })
92+ const setData = () => {
93+ render.value = renderLines(props.mode, props.prev, props.current)
94+ meta.value.splice(render.value.length)
95+ render.value.map((v, index: number) => {
96+ const item = meta.value[index]
97+ meta.value[index] = {
98+ index,
99+ visible: item?.visible || !props.virtualScroll,
100+ top: item?.top || undefined,
101+ height: item?.height || 24
111102 }
112-
113- return acc + curr
114- }, 0)
115-
116- return result
117- }
118-
119- const handleScroll = () => {
120- visibleData.value = getVisibleData()
121- }
122-
123- const setLineHeight = (index: number, height: number) => {
124- const item = source.value.find(item => item.key === index)
125- if (item) {
126- item.height = height
127- }
103+ })
104+ setMeta()
128105 }
129106
130107 onMounted(() => {
131- if (!viewer.value) return
132- viewer.value.addEventListener('scroll', throttle(handleScroll, 500))
133-
134- watch([
135- () => props.mode,
136- () => props.prev,
137- () => props.current
138- ], () => {
139- source.value = renderLines(props.mode, props.prev, props.current).map((render, index) => {
140- return {
141- key: index,
142- render,
143- height: 24
144- }
145- })
146-
147- if (!props.virtualScroll) {
148- if (source.value.length > 500) {
149- console.warn('If there are many lines, please use virtualScroll property.')
150- }
151-
152- visibleData.value = source.value
153- } else {
154- visibleData.value = getVisibleData()
108+ watch(
109+ [
110+ () => props.mode,
111+ () => props.prev,
112+ () => props.current
113+ ],
114+ debounce(setData, props.inputDelay),
115+ {
116+ immediate: true,
117+ deep: true
155118 }
156- }, { immediate: true } )
119+ )
157120 })
158121
159- onBeforeUnmount(() => {
160- if (!viewer.value) return
161- viewer.value.removeEventListener('scroll', throttle(handleScroll, 500))
162- })
122+ const setLineHeight = (index: number, height: number) => {
123+ if (meta.value[index]) {
124+ meta.value[index].height = height
125+ }
126+ }
163127
164128 return {
165- visibleData,
129+ meta,
130+ minHeight,
131+ render,
132+ scrollOptions,
133+ setLineHeight,
166134 viewer,
167- viewerHeight,
168- innerMinHeight,
169- setLineHeight
135+ visible
170136 }
171137 }
172138})
0 commit comments