1 Star 29 Fork 15

ES/JueJin

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
VirtualScroll.vue 5.31 KB
一键复制 编辑 原始数据 按行查看 历史
ES 提交于 1年前 . 添加缺失的函数
<template>
<div class="VirtualScroll-container"
@mouseenter="pause"
@mouseleave="play"
v-resize="setParentSize">
<div :class="['recycle-wrap', needAnimation && animationClass]"
@animationiteration="onAnimationiteration"
:style="{
display: 'flex',
animationPlayState: playState,
animationDuration: duration,
...styles.recycleWrap,
}">
<div class="recycle-item"
:style="{
flex: `0 0 ${handleCssUnit(itemSize)}`,
...styles.recycleItem
}"
v-for="(item, index) in itemPool"
:key="item[keyField] ?? index">
<slot :item="item">
请在默认插槽下使用数据`item`:
{{ item }}
</slot>
</div>
</div>
</div>
</template>
<script setup lang="ts" generic="T extends {
src?: string
[K: string]: any
}">
import { handleCssUnit } from '@jl-org/tool'
import type { ResizeFn } from '@/directives/resize'
/**
* 虚拟自动滚动组件,根据大小
* 动态加载可视范围的数据,防止卡顿
* 使用 动画切割 实现
*/
defineOptions({
inheritAttrs: true,
name: "VirtualScroll",
})
const props = withDefaults(
defineProps<{
data: T[]
dir?: 'x' | 'y'
/**
* 高度或者宽度 根据`dir`决定
* 这个数值必须能被父容器大小 **整除**
*/
itemSize?: number
speed?: number
keyField?: string
}>(),
{
itemSize: 100,
speed: 40,
dir: 'x',
keyField: 'id',
}
)
const
/** 子元素大小总和 */
totalSize = computed(() => {
const len = props.data.length
return props.itemSize * len
}),
parentSize = ref(0),
setParentSize: ResizeFn = ({ width, height }) => {
switch (props.dir) {
case 'x':
parentSize.value = width
break
case 'y':
parentSize.value = height
break
default:
break
}
if (parentSize.value % props.itemSize !== 0) {
throw new Error('itemSize 必须能被父容器大小整除 (itemSize must be divisible by parentSize)')
}
},
/** 一页展示的个数 */
showCount = ref(0),
/** 展示的大小,可能是高度,也可能是宽度 */
showSize = computed(() => showCount.value * props.itemSize),
/** 内容比容器大再滚动 */
needAnimation = computed(() => totalSize.value > parentSize.value),
playState = ref<'paused' | 'running'>('running'),
animationClass = computed(() =>
props.dir === 'x'
? 'animation-x'
: 'animation-y'
),
curIndex = ref(0),
endIndex = computed(() => curIndex.value + showCount.value),
/** 实际的展示数据 */
itemPool = computed(() => props.data.slice(curIndex.value, endIndex.value)),
duration = computed(() => getDuration(parentSize.value, props.speed) + 's')
const styles = computed(() => {
if (props.dir === 'x') {
return {
recycleWrap: {
flexDirection: 'row' as const,
width: handleCssUnit(showSize.value)
},
recycleItem: {
height: '100%',
width: handleCssUnit(props.itemSize)
}
}
}
return {
recycleWrap: {
flexDirection: 'column' as const,
height: handleCssUnit(showSize.value)
},
recycleItem: {
width: '100%',
height: handleCssUnit(props.itemSize)
}
}
})
/** --------------------------------------------------------------------
* 初始化入口
*/
onMounted(() => {
watch(
[props, parentSize],
setData,
{ immediate: true, deep: true }
)
})
/** ---------------------------------------------------------------------------
* 事件
*/
function onAnimationiteration() {
setCurIndex()
}
function play() {
playState.value = 'running'
}
function pause() {
playState.value = 'paused'
}
/** -------------------------------------------------------------------------
* 工具
*/
function setData() {
if (parentSize.value > 0) {
/** 展示两倍长度 再动态切换 */
showCount.value = Math.ceil(parentSize.value / props.itemSize) * 2
}
}
/** 设置动态索引 自动改变展示内容 */
function setCurIndex() {
curIndex.value += Math.floor(showCount.value / 2)
if (curIndex.value >= props.data.length - 1) {
curIndex.value = 0
}
}
/**
* 返回滚动动画时间 单位:s
* @param size 容器大小
* @param speed 每秒滚动距离 单位: px
*/
function getDuration(size = 0, speed: number) {
if (!size) return 0
return size / speed
}
</script>
<style scoped lang="scss">
.VirtualScroll-container {
@include full;
overflow: hidden;
}
.recycle-wrap {
@include flex();
@include full;
}
.animation-x {
animation: scrollX 3s infinite linear;
}
.animation-y {
animation: scrollY 3s infinite linear;
}
@keyframes scrollX {
100% {
transform: translateX(-50%);
}
}
@keyframes scrollY {
100% {
transform: translateY(-50%);
}
}
</style>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/cjl2385/dig-for-gold.git
git@gitee.com:cjl2385/dig-for-gold.git
cjl2385
dig-for-gold
JueJin
master

搜索帮助