style:首页
This commit is contained in:
212
src/components/InfiniteScroll/index.vue
Normal file
212
src/components/InfiniteScroll/index.vue
Normal file
@@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div
|
||||
ref="scrollBox"
|
||||
:class="`infinite-scroll-component-box-${direction}`"
|
||||
:style="{
|
||||
'--speed-': `${speed}s`,
|
||||
mask: `linear-gradient(${degList[direction]}, #000 70%, transparent)`
|
||||
}"
|
||||
>
|
||||
<div class="scroll-content" ref="scrollContent">
|
||||
<template v-if="Array.isArray(content)">
|
||||
<div v-for="(item, index) in content" :key="'arrayFirst' + index" class="loop-item">
|
||||
<slot :item="item" :index="index"></slot>
|
||||
</div>
|
||||
<template v-if="loop">
|
||||
<div v-for="(item, index) in content" class="loop-item" :key="'arrayCopy' + index">
|
||||
<slot :item="item" :index="index"></slot>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot></slot>
|
||||
<slot v-if="loop"></slot>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'top',
|
||||
validate: (value) => ['left', 'top', 'right', 'bottom'].findIndex(value) !== -1
|
||||
},
|
||||
|
||||
content: {
|
||||
type: [String, Array],
|
||||
default: ''
|
||||
},
|
||||
|
||||
mask: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
// 速率倍速,越大越快,默认值20
|
||||
speedRate: {
|
||||
type: Number,
|
||||
default: 20
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
|
||||
let degList = {
|
||||
left: '90deg',
|
||||
top: '180deg',
|
||||
right: '270deg',
|
||||
bottom: '0deg'
|
||||
}
|
||||
// 滚动速度
|
||||
let speed = ref(0)
|
||||
// 是否需要无限滚动
|
||||
let loop = ref(false)
|
||||
// 容器ref
|
||||
let scrollBox = ref()
|
||||
|
||||
watch(
|
||||
() => props.content,
|
||||
() => {
|
||||
loop.value = false
|
||||
init()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 初始化速度,以及是否需要无限滚动
|
||||
const init = async () => {
|
||||
await nextTick()
|
||||
if (props.direction === 'left' || props.direction === 'right') {
|
||||
// 可视区域的宽度
|
||||
const boxWidth = scrollBox.value.offsetWidth
|
||||
// 滚动内容的宽度
|
||||
const itemWidth = scrollBox.value.getElementsByClassName('scroll-content')[0].offsetWidth
|
||||
if (itemWidth >= boxWidth) {
|
||||
loop.value = true
|
||||
speed.value = itemWidth / props.speedRate
|
||||
} else {
|
||||
speed.value = 0
|
||||
scrollBox.value.getElementsByClassName('scroll-content')[0].style.transform =
|
||||
'translateX(0)'
|
||||
loop.value = false
|
||||
}
|
||||
} else {
|
||||
const boxHeight = scrollBox.value.offsetHeight
|
||||
const itemHeight = scrollBox.value.getElementsByClassName('scroll-content')[0].offsetHeight
|
||||
if (itemHeight >= boxHeight) {
|
||||
loop.value = true
|
||||
speed.value = itemHeight / props.speedRate
|
||||
} else {
|
||||
speed.value = 0
|
||||
scrollBox.value.getElementsByClassName('scroll-content')[0].style.transform =
|
||||
'translateY(0)'
|
||||
loop.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.infinite-scroll-component-box-left,
|
||||
.infinite-scroll-component-box-right {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.scroll-content {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
}
|
||||
}
|
||||
.infinite-scroll-component-box-top,
|
||||
.infinite-scroll-component-box-bottom {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.scroll-content {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
.loop-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.infinite-scroll-component-box-left .scroll-content {
|
||||
flex-direction: row;
|
||||
animation: var(--speed-) move-left linear infinite;
|
||||
|
||||
@keyframes move-left {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.infinite-scroll-component-box-right .scroll-content {
|
||||
flex-direction: row-reverse;
|
||||
animation: var(--speed-) move-right linear infinite;
|
||||
|
||||
@keyframes move-right {
|
||||
0% {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.infinite-scroll-component-box-top .scroll-content {
|
||||
flex-direction: column;
|
||||
animation: var(--speed-) move-top linear infinite;
|
||||
|
||||
@keyframes move-top {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.infinite-scroll-component-box-bottom .scroll-content {
|
||||
flex-direction: column-reverse;
|
||||
animation: var(--speed-) move-bottom linear infinite;
|
||||
|
||||
@keyframes move-bottom {
|
||||
0% {
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user