diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss index 827f2f7..efed171 100644 --- a/src/assets/styles/index.scss +++ b/src/assets/styles/index.scss @@ -20,6 +20,14 @@ body { height: 600px; margin-bottom: 50px; } + +/* 移动端 Banner 自适应高度 */ +@media screen and (max-width: 999px) { + .banner { + height: auto; + margin-bottom: 20px; + } +} .page { width: 100%; height: 100%; diff --git a/src/components/Banner/index.vue b/src/components/Banner/index.vue index edae95e..a4f53a7 100644 --- a/src/components/Banner/index.vue +++ b/src/components/Banner/index.vue @@ -19,6 +19,7 @@ const props = defineProps({ diff --git a/src/components/Swiper/composable.js b/src/components/Swiper/composable.js new file mode 100644 index 0000000..e231a49 --- /dev/null +++ b/src/components/Swiper/composable.js @@ -0,0 +1,125 @@ +import {ref, computed, watch, nextTick, getCurrentInstance, onUnmounted} from 'vue' + +/** + * Swiper 公用逻辑 composable + * @param {object} props - 组件 props + * @param {object} model - v-model ref (currentPage) + * @param {function} emit - emit 函数 + */ +export function useSwiper(props, model, emit) { + const instance = getCurrentInstance() + const $fontSize = instance.appContext.config.globalProperties.$fontSize + const trackRef = ref(null) + let autoPlayTimer = null + + /* ---------- 计算属性 ---------- */ + const itemWidth = computed(() => $fontSize(props.sourceWidth)) + const itemHeight = computed(() => $fontSize(props.sourceHeight)) + const itemGap = computed(() => $fontSize(props.sourceGap)) + const itemTotalWidth = computed(() => itemWidth.value + itemGap.value) + const viewPortWidth = computed(() => props.pageSize * itemWidth.value + (props.pageSize - 1) * itemGap.value + 'px') + const trackWidth = computed(() => props.data.length * itemTotalWidth.value - itemGap.value + 'px') + const totalPages = computed(() => props.data.length - props.pageSize + 1) + + /* ---------- 方法 ---------- */ + function clickTitle() { + emit('title-click') + } + + function translate(page) { + if (!trackRef.value) return + trackRef.value.style.transition = `transform ${props.transitionDuration}ms ease` + trackRef.value.style.transform = `translateX(-${itemTotalWidth.value * (page - 1)}px)` + } + + function goToPage(page) { + model.value = Number(page) + } + + function nextPage() { + const next = model.value < totalPages.value ? model.value + 1 : 1 + goToPage(next) + } + + function prevPage() { + const prev = model.value > 1 ? model.value - 1 : totalPages.value + goToPage(prev) + } + + function handleItemClick(item, index) { + emit('item-click', item, index) + } + + function handleItemHover(item, index) { + clearInterval(autoPlayTimer) + autoPlayTimer = null + emit('item-hover', item, index) + } + + function handleItemHoverLeave() { + startAutoPlay() + } + + function startAutoPlay() { + if (!props.autoPlay) return + stopAutoPlay() + autoPlayTimer = setInterval(nextPage, 3000) + } + + function stopAutoPlay() { + if (autoPlayTimer) { + clearInterval(autoPlayTimer) + autoPlayTimer = null + } + } + + /* 移动端触摸事件 */ + function handleItemTouchStart(item, index) { + clearInterval(autoPlayTimer) + autoPlayTimer = null + emit('item-hover', item, index) + } + + function handleItemTouchEnd() { + startAutoPlay() + } + + /* ---------- 监听器 ---------- */ + watch(model, (newVal, oldVal) => { + if (newVal !== oldVal) { + nextTick(() => translate(newVal)) + } + }, {immediate: true}) + + watch(() => props.autoPlay, (autoPlay) => { + autoPlay ? startAutoPlay() : stopAutoPlay() + }, {immediate: true}) + + watch(() => props.data.length, (newLen, oldLen) => { + if (newLen !== oldLen && model.value !== 1) { + model.value = 1 + } + }) + + onUnmounted(stopAutoPlay) + + return { + trackRef, + itemWidth, + itemHeight, + itemGap, + itemTotalWidth, + viewPortWidth, + trackWidth, + totalPages, + clickTitle, + goToPage, + nextPage, + prevPage, + handleItemClick, + handleItemHover, + handleItemHoverLeave, + handleItemTouchStart, + handleItemTouchEnd, + } +} diff --git a/src/components/Swiper/mobile/index.vue b/src/components/Swiper/mobile/index.vue new file mode 100644 index 0000000..f0d4638 --- /dev/null +++ b/src/components/Swiper/mobile/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/src/components/swiper/index.vue b/src/components/Swiper/pc/index.vue similarity index 55% rename from src/components/swiper/index.vue rename to src/components/Swiper/pc/index.vue index 96e5baf..9fbb1b1 100644 --- a/src/components/swiper/index.vue +++ b/src/components/Swiper/pc/index.vue @@ -1,7 +1,6 @@