网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
计算startIndex
和endIndex
现在,我们可以按照之前的计算方式来确定要展示的startIndex和endIndex。具体情况如下:
- 滚动的距离在knownHeight(已知总高度)内
如果起始索引到结束索引都小于已知总高度,我们可以精确计算出startIndex和endIndex。
当只有起始索引小于已知总高度时,对于剩余部分,我们可以使用preHeight进行模拟计算。
let i = 0
let res = 0
while (res <= scrollTop.value) {
res += allHeightList.value[i]
i++
}
startIndex.value = i - 1
if (knownHeight.value - res >= height) {
while (res <= scrollTop.value + height) {
res += allHeightList.value[i]
i++
}
endIndex.value = i
} else {
endIndex.value = allHeightList.value.length + Math.ceil(height - (knownHeight.value - res) / preHeight.value)
}
- 滚动的距离超出
knownHeight
(已知总高度)
在这种情况下,我们无法准确计算startIndex和endIndex,只能通过preHeight进行模拟计算。
startIndex.value = allHeightList.value.length
needShowLength.value = Math.ceil(height / preHeight.value)
endIndex.value = startIndex.value + needShowLength.value
演示效果
下面让我们简单看一下使用该方法的效果(使用了4万条数据)
请注意,这种方法能够应对子项高度不确定的情况,但在处理超出已知总高度的滚动距离时稍显不足。
GuDynamicHeightList源码
<template>
<div
ref="guList"
class="gu-list"
@scroll="onScroll"
>
<ul
ref="virtualList"
class="gu-virtual-list"
:style="{
height:ListHeight + 'px'
}"
>
<li
v-for="(item,idx) in showList"
:key="item[field.key]"
class="gu-virtual-list-item"
:class="[active == item[field.value] ? 'active' :'']"
:style="{
top:`${ reduceHeight(startIndex+idx) }px`
}"
:idx="idx"
@click="onClick(item)"
>
<slot
name="content"
:item="item"
>
{{ item[field.label] }}
</slot>
</li>
</ul>
</div>
</template>
<script lang='ts' setup name="GuDynamicHeightList">
import { toRefs, ref, computed, onMounted, onUpdated } from 'vue'
import { Obj } from '../../types/utilsType'
export type ReplaceFieldType = {
children?:string,
value?:string,
label?:string,
key?:string,
[field:string]:any
}
interface VirtualProps {
preHeight?:number,
list:Obj[],
replaceField?: ReplaceFieldType
}
const defaultField = {
children: 'children',
value: 'value',
label: 'label',
key: 'key',
}
const props = withDefaults(defineProps<VirtualProps>(), {
preHeight: 26,
list: () => ([]),
replaceField: () => ({
children: 'children',
value: 'value',
label: 'label',
key: 'key',
}),
})
const { list, replaceField: propField, preHeight } = toRefs(props)
// 所有项的真实高度
const allHeightList = ref<number[]>([])
const knownHeight = computed(() => allHeightList.value.reduce((p, c) => {
p += c
return p
}, 0))
// 总高度
const ListHeight = computed(() => {
let idx = allHeightList.value.length
return knownHeight.value + (list.value.length - idx) \* preHeight.value
})
const field = computed(() => ({
...defaultField,
...propField.value,
}))
const active = ref('')
const emits = defineEmits(['onClickItem'])
const onClick = (item:Obj) => {
active.value = item[field.value.value]
emits('onClickItem', item)
}
// 展示列表data
const showList = ref<Obj[]>([])
const guList = ref()
// 裁剪数组开始项
const startIndex = ref(0)
// 裁剪数组结束项
const endIndex = ref(0)
// 计算需要展示的元素个数
const needShowLength = ref(0)
const virtualList = ref()
const scrollTop = ref(0)
const onScroll = () => {
const { height } = guList.value.getBoundingClientRect()
scrollTop.value = guList.value.scrollTop
if (scrollTop.value + height > knownHeight.value) {
startIndex.value = allHeightList.value.length
![img](https://img-blog.csdnimg.cn/img_convert/d72f7cfdaf63429a31701413dfec3ce1.png)
![img](https://img-blog.csdnimg.cn/img_convert/7c04b402077e3e46c5efeca67f43eb82.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
难做到真正的技术提升。**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**