201 lines
4.0 KiB
Vue
201 lines
4.0 KiB
Vue
<!-- HorizontalDateList.vue -->
|
|
<template>
|
|
<div class="horizontal-date-wrapper">
|
|
<div
|
|
class="nav-button prev-button"
|
|
:class="{ disabled: !canScrollPrev }"
|
|
@click="scrollPrev"
|
|
>
|
|
<img :src="prevIcon" alt="Previous" />
|
|
</div>
|
|
|
|
<div ref="scrollWrapper" class="scroll-wrapper">
|
|
<div ref="scrollContent" class="scroll-content">
|
|
<slot></slot>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="nav-button next-button"
|
|
:class="{ disabled: !canScrollNext }"
|
|
@click="scrollNext"
|
|
>
|
|
<img :src="nextIcon" alt="Next" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import IconPrev from '@/static/launches/icon_prev.png';
|
|
import IconNext from '@/static/launches/icon_next.png';
|
|
import IconPrevDisabled from '@/static/launches/icon_prev_disabled.png';
|
|
import IconNextDisabled from '@/static/launches/icon_next_disabled.png';
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
scrollPosition: 0,
|
|
maxScroll: 0,
|
|
canScrollPrev: false,
|
|
canScrollNext: true
|
|
}
|
|
},
|
|
computed: {
|
|
prevIcon() {
|
|
return this.canScrollPrev ? IconPrev : IconPrevDisabled;
|
|
},
|
|
nextIcon() {
|
|
return this.canScrollNext ? IconNext : IconNextDisabled;
|
|
}
|
|
},
|
|
mounted() {
|
|
this.initScroll();
|
|
window.addEventListener('resize', this.updateScrollState);
|
|
},
|
|
beforeDestroy() {
|
|
window.removeEventListener('resize', this.updateScrollState);
|
|
},
|
|
methods: {
|
|
initScroll() {
|
|
this.updateScrollState();
|
|
},
|
|
|
|
forceUpdate() {
|
|
this.updateScrollState();
|
|
},
|
|
|
|
updateScrollState() {
|
|
this.$nextTick(() => {
|
|
const wrapper = this.$refs.scrollWrapper;
|
|
const content = this.$refs.scrollContent;
|
|
|
|
if (wrapper && content) {
|
|
// 重置滚动位置
|
|
wrapper.scrollLeft = 0;
|
|
this.scrollPosition = 0;
|
|
|
|
// 重新计算最大滚动距离
|
|
this.maxScroll = Math.max(0, content.offsetWidth - wrapper.offsetWidth);
|
|
|
|
// 更新按钮状态
|
|
this.updateButtonStates();
|
|
}
|
|
});
|
|
},
|
|
|
|
updateButtonStates() {
|
|
const wrapper = this.$refs.scrollWrapper;
|
|
if (wrapper) {
|
|
this.scrollPosition = wrapper.scrollLeft;
|
|
this.canScrollPrev = this.scrollPosition > 0;
|
|
this.canScrollNext = this.scrollPosition < this.maxScroll;
|
|
}
|
|
},
|
|
|
|
scrollPrev() {
|
|
const wrapper = this.$refs.scrollWrapper;
|
|
if (!wrapper || wrapper.scrollLeft <= 0) return;
|
|
|
|
const scrollAmount = wrapper.offsetWidth * 0.8;
|
|
const newPosition = Math.max(0, wrapper.scrollLeft - scrollAmount);
|
|
|
|
wrapper.scrollTo({
|
|
left: newPosition,
|
|
behavior: 'smooth'
|
|
});
|
|
|
|
// 更新状态
|
|
setTimeout(() => {
|
|
this.updateButtonStates();
|
|
}, 300);
|
|
},
|
|
|
|
scrollNext() {
|
|
const wrapper = this.$refs.scrollWrapper;
|
|
if (!wrapper) return;
|
|
|
|
const scrollAmount = wrapper.offsetWidth * 0.8;
|
|
const newPosition = Math.min(this.maxScroll, wrapper.scrollLeft + scrollAmount);
|
|
|
|
wrapper.scrollTo({
|
|
left: newPosition,
|
|
behavior: 'smooth'
|
|
}
|
|
);
|
|
|
|
// 更新状态
|
|
setTimeout(() => {
|
|
this.updateButtonStates();
|
|
}, 300);
|
|
}
|
|
},
|
|
watch: {
|
|
// 监听插槽内容变化
|
|
'$slots.default'() {
|
|
this.updateScrollState();
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<!-- HorizontalDateList.vue -->
|
|
<style scoped lang="scss">
|
|
.horizontal-date-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
width: 100%;
|
|
|
|
.nav-button {
|
|
width: 44px;
|
|
height: 44px;
|
|
cursor: pointer;
|
|
background-color: #FFFFFF;
|
|
border-radius: 4px;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
&:active {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
img {
|
|
width: 44px;
|
|
height: 44px;
|
|
}
|
|
|
|
&.disabled {
|
|
cursor: not-allowed;
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
|
|
.scroll-wrapper {
|
|
flex: 1; /* 使用flex而不是固定宽度 */
|
|
min-width: 0; /* 允许flex项目收缩 */
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
position: relative;
|
|
|
|
/* 隐藏滚动条 */
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
|
|
&::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.scroll-content {
|
|
display: flex; /* 使用flex布局 */
|
|
gap: 12px; /* 设置元素间距 */
|
|
white-space: nowrap;
|
|
width: max-content; /* 确保内容宽度正确 */
|
|
}
|
|
}
|
|
</style>
|
|
|