vue组件系列-列表左右箭头滚动(vue3+ts)
<template> <div class="list-wrapper" ref="allListRef"> <div v-if="showArrow && listSource.length > minArrowItemsCount" @click="scrollLeft" class="arrow" :class="{'disable': leftArrowDisabled }" ><</div> <div class="list" ref="listRef" :class="{'overflowX': showArrow}"> <div class="items-box" ref="itemsRef"> <slot></slot> </div> </div> <div v-if="showArrow && listSource.length > minArrowItemsCount" @click="scrollRight" class="arrow" :class="{'disable': rightArrowDisabled }" >></div> </div> </template> <script setup lang="ts"> import { nextTick, reactive, ref } from 'vue' const props = withDefaults( defineProps<{ listSource: Array<any>, showArrow: boolean, minArrowItemsCount: number, //最小项目数 超过才显示箭头 itemWidth: number, //列表每一项的宽度(包含每项间距) moveItemsCount: number //每次点击箭头移动的item数量 }>(), { showArrow: true, minArrowItemsCount: 5, itemWidth: 96, moveItemsCount: 1 } ) const listRef = ref(null) const itemsRef = ref(null) const leftArrowDisabled = ref(true) const rightArrowDisabled = ref(false) // 左滑动逻辑 const scrollLeft = () => { nextTick(() => { if (listRef.value && itemsRef.value) { const allLength = props.listSource.length * props.itemWidth const boxLength = listRef.value.clientWidth const moveDistance = props.moveItemsCount * props.itemWidth if (allLength < boxLength) return rightArrowDisabled.value = false const listEl = itemsRef.value const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left)) if (leftMove + boxLength - moveDistance < boxLength) { // 到最开始的时候 listEl.style.left = '0px' leftArrowDisabled.value = true } else { listEl.style.left = '-' + (leftMove - moveDistance) + 'px' leftArrowDisabled.value = false } } }) } // 右滑动逻辑 const scrollRight = () => { nextTick(() => { if (listRef.value && itemsRef.value) { const allLength = props.listSource.length * props.itemWidth const boxLength = listRef.value.clientWidth const moveDistance = props.moveItemsCount * props.itemWidth if (allLength < boxLength) return leftArrowDisabled.value = false const listEl = itemsRef.value const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left)) if (leftMove + boxLength + moveDistance > allLength) { listEl.style.left = '-' + (allLength - boxLength) + 'px' rightArrowDisabled.value = true } else { listEl.style.left = '-' + (leftMove + moveDistance) + 'px' rightArrowDisabled.value = false } } }) } </script> <style scoped lang="less"> .list-wrapper { width: 100%; display: flex; justify-content: space-between; .list { margin-left:8px; margin-right:8px; width: calc(100% - 48px); } .overflowX { overflow-x: hidden; } .items-box { display: flex; transform: all 1s; position: relative; left: 0; transition: left .5s; width: 100%; } .arrow { width: 16px; height: 60px; background: #FFFFFF; border-radius: 2px; border: 1px solid #E5E5E5; line-height: 60px; text-align: center; font-size: 16px; color: #333333; cursor:pointer; user-select: none; -webkit-user-select: none; } .arrow:not(.disable):hover, .arrow:not(.disable):active { background: #FAFAFA; } .disable { color:#E5E5E5; cursor:default; } } </style>