mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-19 18:59:31 +08:00
重写SlideView组件
This commit is contained in:
131
src/components/slide/SlideView.vue
Normal file
131
src/components/slide/SlideView.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<script lang="ts" setup>
|
||||
import SlideViewTitle from '@/components/slide/SlideViewTitle.vue'
|
||||
|
||||
// 输入参数
|
||||
const props = defineProps({
|
||||
linkurl: String,
|
||||
title: String,
|
||||
})
|
||||
|
||||
// 元素
|
||||
const slideview_content = ref()
|
||||
// 分页切换状态
|
||||
const disabled = ref(0)
|
||||
// 所有卡片数量
|
||||
let slide_card_length: number
|
||||
// 卡片间距
|
||||
let slide_gap_px: number
|
||||
// 卡片宽度
|
||||
let card_width: number
|
||||
// 容器最多显示N张卡片
|
||||
let card_max: number
|
||||
// 当前定位
|
||||
let card_current: number
|
||||
|
||||
// 分页切换
|
||||
function slideNext(next: boolean) {
|
||||
let run_to_left_px
|
||||
if (next) {
|
||||
const card_index = card_current + card_max
|
||||
run_to_left_px = card_index * card_width
|
||||
if (run_to_left_px >= slideview_content.value.scrollWidth - slideview_content.value.clientWidth)
|
||||
run_to_left_px = slideview_content.value.scrollWidth - slideview_content.value.clientWidth
|
||||
// console.log(`最多显示: ${card_max} 当前起点: ${card_current} 目标起点: ${card_index} 卡片宽度: ${card_width}`)
|
||||
}
|
||||
else {
|
||||
const card_index = card_current - card_max
|
||||
run_to_left_px = card_index * card_width
|
||||
if (run_to_left_px <= 0)
|
||||
run_to_left_px = 0
|
||||
// console.log(`最多显示: ${card_max} 当前起点: ${card_current} 目标起点: ${card_index} 卡片宽度: ${card_width}`)
|
||||
}
|
||||
slideview_content.value.scrollTo({
|
||||
top: 0,
|
||||
left: run_to_left_px,
|
||||
behavior: 'smooth',
|
||||
})
|
||||
}
|
||||
|
||||
// 计算最大显示数量
|
||||
function countMaxNumber() {
|
||||
slide_card_length = slideview_content.value.children.length
|
||||
card_width = slideview_content.value.firstElementChild.getBoundingClientRect().width
|
||||
slide_gap_px = (slideview_content.value.scrollWidth / slide_card_length) - card_width
|
||||
card_width += slide_gap_px
|
||||
card_max = Math.trunc(slideview_content.value.clientWidth / card_width)
|
||||
countDisabled()
|
||||
}
|
||||
|
||||
// 修改分页切换按钮状态
|
||||
function countDisabled() {
|
||||
card_current = slideview_content.value.scrollLeft === 0 ? 0 : Math.trunc((slideview_content.value.scrollLeft + card_width / 2) / card_width)
|
||||
if (slide_card_length * card_width <= slideview_content.value.clientWidth)
|
||||
disabled.value = 3
|
||||
else if (slideview_content.value.scrollLeft === 0)
|
||||
disabled.value = 0
|
||||
else if (slideview_content.value.scrollLeft >= slideview_content.value.scrollWidth - slideview_content.value.clientWidth - 2)
|
||||
disabled.value = 2
|
||||
|
||||
else
|
||||
disabled.value = 1
|
||||
}
|
||||
|
||||
// 组件加载完成
|
||||
onMounted(() => {
|
||||
// 初次获取元素参数
|
||||
countMaxNumber()
|
||||
// 窗口大小发生改变时
|
||||
window.addEventListener('resize', countMaxNumber)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
// 卸载事件
|
||||
window.removeEventListener('resize', countMaxNumber)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-between mt-3">
|
||||
<slot name="title">
|
||||
<SlideViewTitle v-bind="props" />
|
||||
</slot>
|
||||
<div v-if="disabled !== 3" class="me-1 d-none d-md-flex">
|
||||
<VBtn
|
||||
class="rounded-circle"
|
||||
variant="text"
|
||||
icon="mdi-chevron-left"
|
||||
color="grey"
|
||||
:disabled="disabled === 0"
|
||||
@click="slideNext(false)"
|
||||
/>
|
||||
<VBtn
|
||||
class="rounded-circle"
|
||||
variant="text"
|
||||
icon="mdi-chevron-right"
|
||||
color="grey"
|
||||
:disabled="disabled === 2"
|
||||
@click="slideNext(true)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref="slideview_content"
|
||||
class="slideview_content grid grid-rows-1 grid-flow-col gap-4 p-3"
|
||||
@scroll="countDisabled"
|
||||
>
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.slideview_content {
|
||||
-ms-overflow-style: none !important;
|
||||
overflow-x: scroll !important;
|
||||
overflow-y: hidden !important;
|
||||
overscroll-behavior-x: contain !important;
|
||||
scrollbar-width: none !important;
|
||||
}
|
||||
|
||||
.slideview_content::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
24
src/components/slide/SlideViewTitle.vue
Normal file
24
src/components/slide/SlideViewTitle.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script lang="ts" setup>
|
||||
// 输入参数
|
||||
const props = defineProps({
|
||||
linkurl: String,
|
||||
title: String,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="ms-1"
|
||||
>
|
||||
<RouterLink
|
||||
:to="props.linkurl ? props.linkurl : ''"
|
||||
class="slider-title"
|
||||
>
|
||||
<span>{{ props.title }}</span>
|
||||
<VIcon
|
||||
icon="mdi-arrow-right-circle-outline"
|
||||
class="ms-1"
|
||||
/>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user