Auto-Scroll-List 组件设计与实现分析
gitee代码仓库
https://gitee.com/chennaiyuan/dayup-record/tree/master/%E4%B8%80%E4%BA%9B%E7%BB%84%E4%BB%B6/auto-scroll-list
1. 组件概述
我们封装的 AutoScrollList
是一个自动滚动列表组件,主要用于展示需要自动循环滚动的数据项,如通知、告警、任务等信息。该组件采用了组件与逻辑分离的设计思路,通过自定义 Hook 实现核心滚动逻辑,提高了代码的可复用性和灵活性。除了依赖 Vue3 和 Less 这种常规组件,可以开封即用。
2. 架构设计
组件采用了"关注点分离"的设计理念,将 UI 表现与业务逻辑分开:
核心架构特点:
- 组件与逻辑分离:核心滚动逻辑被抽象到
useAutoScroll
Hook 中 - 可组合性:Hook 可独立使用,也可以集成在组件中
- 插槽设计:通过 Vue 的插槽系统实现内容的高度自定义
实现逻辑与数据流
核心方法和状态详解
3. 核心实现逻辑
useAutoScroll Hook
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
export interface AutoScrollOptions {
items: any[]; // 数据项数组
itemHeight: number; // 单项高度
itemGap?: number; // 项目间距
visibleItems: number; // 可见项目数
scrollInterval?: number; // 滚动间隔(毫秒)
transitionDuration?: number; // 过渡动画时长(毫秒)
autoScroll?: boolean; // 是否自动滚动
}
export function useAutoScroll(options: AutoScrollOptions) {
const {
items,
itemHeight,
itemGap = 0,
visibleItems,
scrollInterval = 3000,
transitionDuration = 500,
autoScroll = true
} = options;
// 状态管理
const currentIndex = ref(0);
const isSliding = ref(false);
const timer = ref<number | null>(null);
// 计算属性
const displayItems = computed(() => {
const result = [];
const totalItems = items.length;
if (totalItems === 0) return [];
// 当前显示的项目
for (let i = 0; i < visibleItems + 1; i++) {
const index = (currentIndex.value + i) % totalItems;
result.push({
...items[index],
key: `${items[index].id}-${index}-${i}`, // 确保key的唯一性
preload: i === visibleItems // 标记预加载项
});
}
return result;
});
// 计算位置
const getItemPosition = (index: number) => {
return index * (itemHeight + itemGap);
};
// 控制方法
const startScroll = () => {
if (timer.value || items.length <= visibleItems) return;
timer.value = window.setInterval(() => {
isSliding.value = true;
setTimeout(() => {
currentIndex.value = (currentIndex.value + 1) % items.length;
isSliding.value = false;
}, transitionDuration);
}, scrollInterval);
};
const stopScroll = () => {
if (timer.value) {
clearInterval(timer.value);
timer.value = null;
}
};
// 生命周期钩子
onMounted(() => {
if (autoScroll && items.length > visibleItems) {
startScroll();
}
});
onBeforeUnmount(() => {
stopScroll();
});
return {
displayItems,
isSliding,
currentIndex,
getItemPosition,
startScroll,
stopScroll
};
}
滚动原理与动画流程
组件实现
<template>
<div
class="auto-scroll-list"
:style="{ height: `${containerHeight}px` }"
>
<template v-if="displayItems.length > 0">
<slot
v-for="(item, index) in displayItems"
:key="item.key"
name="item"
:item="item"
:position="getItemPosition(index)"
:is-sliding="isSliding"
:is-preload="item.preload"
></slot>
</template>
<template v-else>
<slot name="empty"></slot>
</template>
</div>
</template>
<script setup lang="ts">
import { useAutoScroll } from './useAutoScroll';
const props = defineProps({
items: {
type: Array,
required: true
},
itemHeight: {
type: Number,
required: true
},
itemGap: {
type: Number,
default: 0
},
containerHeight: {
type: Number,
required: true
},
visibleItems: {
type: Number,
required: true
},
scrollInterval: {
type: Number,
default: 3000
},
transitionDuration: {
type: Number,
default: 500
},
autoScroll: {
type: Boolean,
default: true
}
});
const {
displayItems,
isSliding,
getItemPosition,
startScroll,
stopScroll
} = useAutoScroll({
items: props.items,
itemHeight: props.itemHeight,
itemGap: props.itemGap,
visibleItems: props.visibleItems,
scrollInterval: props.scrollInterval,
transitionDuration: props.transitionDuration,
autoScroll: props.autoScroll
});
// 暴露方法
defineExpose({
startScroll,
stopScroll
});
</script>
<style lang="less" scoped>
.auto-scroll-list {
position: relative;
overflow: hidden;
}
</style>
4. 使用示例
以下是组件的三种典型使用场景:
基础用法
<auto-scroll-list
:items="notificationItems"
:item-height="80"
:container-height="250"
:visible-items="3"
>
<template #item="{ item, position, isSliding, isPreload }">
<div
class="notification-item"
:style="{ transform: `translateY(${position}px)` }"
:class="{ sliding: isSliding, preload: isPreload }"
>
<div class="title">{{ item.title }}</div>
<div class="content">{{ item.content }}</div>
</div>
</template>
<template #empty>
<div class="empty-message">暂无通知</div>
</template>
</auto-scroll-list>
自定义样式的告警列表
<auto-scroll-list
:items="alertItems"
:item-height="80"
:item-gap="10"
:container-height="250"
:visible-items="3"
:scroll-interval="5000"
>
<template #item="{ item, position, isSliding, isPreload }">
<div
class="alert-item"
:class="{
'high-priority': item.priority === 'high',
'medium-priority': item.priority === 'medium',
'low-priority': item.priority === 'low',
sliding: isSliding,
preload: isPreload
}"
:style="{ transform: `translateY(${position}px)` }"
>
<div class="alert-badge">{{ item.priority === 'high' ? '!' : '⚠' }}</div>
<div class="alert-content">
<div class="alert-title">{{ item.title }}</div>
<div class="alert-message">{{ item.message }}</div>
</div>
</div>
</template>
</auto-scroll-list>
直接使用 Hook 自定义实现
<template>
<div class="custom-list" :style="{ height: `${containerHeight}px` }">
<div
v-for="(item, index) in displayItems"
:key="item.key"
class="task-item"
:style="{ transform: `translateY(${getItemPosition(index)}px)` }"
:class="{ sliding: isSliding, preload: item.preload }"
>
<!-- 自定义内容 -->
</div>
</div>
</template>
<script setup>
import { useAutoScroll } from './useAutoScroll';
// 自定义实现
const containerHeight = 250;
const {
displayItems,
getItemPosition,
isSliding,
startScroll,
stopScroll
} = useAutoScroll({
items: taskItems.value,
itemHeight: 80,
itemGap: 10,
visibleItems: 3,
autoScroll: true
});
</script>
用户交互过程
5. 技术优劣分析
优势
- 关注点分离:将滚动逻辑与UI表现分离,提高代码可维护性
- 高度复用性:Hook 可独立使用,适用于不同场景
- 良好的扩展性:通过插槽系统支持高度自定义的内容
- 配置灵活:支持多种滚动参数配置,适应不同业务需求
- 无外部依赖:不依赖第三方库,减少项目体积
劣势
- 性能考虑:对于大量数据,需要考虑虚拟列表优化
- 动画限制:当前仅支持垂直方向滚动,水平滚动需额外开发
- 复杂场景适应性:对于需要拖拽或交互复杂的场景支持有限
- 不支持嵌套列表:当前设计不适合嵌套滚动列表的场景
- 浏览器兼容性:使用了现代CSS特性,可能需要额外的兼容处理
性能分析
6. 可改进方向
技术路线演进
timeline
title AutoScrollList 组件演进路线
section 当前版本
1.0 : 基础垂直滚动功能
Hook与组件分离设计
插槽系统支持
section 短期迭代
1.1 : 水平滚动支持
性能优化
1.2 : 响应式增强
多种动画效果
section 中期规划
2.0 : 虚拟列表实现
多方向滚动
拖拽排序支持
section 长期目标
3.0 : 完整无障碍支持
高级自定义API
更多交互模式
- 虚拟列表支持:对大数据量进行优化,只渲染可视区域的数据
- 水平滚动支持:扩展当前的垂直滚动逻辑,支持水平方向滚动
- 更多交互方式:添加拖拽、手势支持等交互方式
- 动画多样化:提供更多滚动动画效果选择
- 响应式支持增强:更好地适应不同设备和屏幕尺寸
- 无障碍支持:增加对屏幕阅读器的支持,提高可访问性
7. 总结
AutoScrollList
组件通过组件与逻辑分离的设计,实现了一个灵活、可复用的自动滚动列表解决方案。它的核心价值在于:
- 简化复杂逻辑:封装了滚动、位置计算、过渡动画等复杂逻辑
- 提高开发效率:通过简单配置即可实现自动滚动效果
- 保持灵活性:支持多种自定义方式,适应不同业务场景
以下是组件实现的关键技术点:
mindmap
root((AutoScrollList))
Hook设计
状态管理
currentIndex
isSliding
timer
生命周期集成
自动启动/停止
返回值设计
按需使用
滚动机制
定时器控制
缓动动画
预加载机制
组件设计
插槽系统
item插槽
empty插槽
Props设计
必要参数
可选配置
样式实现
绝对定位
CSS变换
过渡效果
虽然存在一些局限性,但对于通知、公告、提醒等信息轮播的场景,该组件提供了一个简洁而有效的解决方案。通过未来的迭代优化,可以进一步提升组件的适用范围和性能表现。