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"><slotv-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 }"><divclass="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 }"><divclass="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. 可改进方向
技术路线演进
timelinetitle AutoScrollList 组件演进路线section 当前版本1.0 : 基础垂直滚动功能Hook与组件分离设计插槽系统支持section 短期迭代1.1 : 水平滚动支持性能优化1.2 : 响应式增强多种动画效果section 中期规划2.0 : 虚拟列表实现多方向滚动拖拽排序支持section 长期目标3.0 : 完整无障碍支持高级自定义API更多交互模式
- 虚拟列表支持:对大数据量进行优化,只渲染可视区域的数据
- 水平滚动支持:扩展当前的垂直滚动逻辑,支持水平方向滚动
- 更多交互方式:添加拖拽、手势支持等交互方式
- 动画多样化:提供更多滚动动画效果选择
- 响应式支持增强:更好地适应不同设备和屏幕尺寸
- 无障碍支持:增加对屏幕阅读器的支持,提高可访问性
7. 总结
AutoScrollList
组件通过组件与逻辑分离的设计,实现了一个灵活、可复用的自动滚动列表解决方案。它的核心价值在于:
- 简化复杂逻辑:封装了滚动、位置计算、过渡动画等复杂逻辑
- 提高开发效率:通过简单配置即可实现自动滚动效果
- 保持灵活性:支持多种自定义方式,适应不同业务场景
以下是组件实现的关键技术点:
mindmaproot((AutoScrollList))Hook设计状态管理currentIndexisSlidingtimer生命周期集成自动启动/停止返回值设计按需使用滚动机制定时器控制缓动动画预加载机制组件设计插槽系统item插槽empty插槽Props设计必要参数可选配置样式实现绝对定位CSS变换过渡效果
虽然存在一些局限性,但对于通知、公告、提醒等信息轮播的场景,该组件提供了一个简洁而有效的解决方案。通过未来的迭代优化,可以进一步提升组件的适用范围和性能表现。