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 @@
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
@@ -168,7 +45,6 @@ onUnmounted(stopAutoPlay)
{{ title }}
-