对接数据
This commit is contained in:
200
components/HorizontalDateList.vue
Normal file
200
components/HorizontalDateList.vue
Normal file
@ -0,0 +1,200 @@
|
||||
<!-- 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>
|
||||
|
||||
Reference in New Issue
Block a user