<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>