Skip to content

Vue Simple Swiper

一个轻量级且易于使用的 Vue 3 轮播图组件,支持触摸手势、键盘控制和自动播放功能。

特性

  • 🚀 轻量级 - 简洁高效的实现
  • 📱 键盘控制 - 支持左右箭头键导航
  • 🎯 自动播放 - 可配置的自动轮播功能
  • 🔄 无限循环 - 支持无限滚动模式
  • 🖼️ 缩略图导航 - 底部缩略图预览和跳转
  • 🎨 自定义按钮 - 支持自定义左右导航按钮
  • 📦 TypeScript - 完整的类型支持

安装

bash
npm install vue3-xm

在线演示

基础演示

基础轮播图

这是一个基础的轮播图示例,展示默认配置和基本功能。

功能说明

  • 🖱️ 点击左右按钮切换图片
  • ⌨️ 使用键盘左右箭头键控制
  • 🖼️ 点击底部缩略图跳转
  • 📱 支持触摸手势(移动端)
查看代码
vue
<template>
    <div class="demo-container">
        <h3>基础轮播图</h3>
        <p>这是一个基础的轮播图示例,展示默认配置和基本功能。</p>

        <div class="swiper-wrapper">
            <SwiperSimple :img-list="basicImages" :auto-play="false" :keys-control="true" :infinite="false" />
        </div>

        <div class="info-panel">
            <h4>功能说明</h4>
            <ul>
                <li>🖱️ 点击左右按钮切换图片</li>
                <li>⌨️ 使用键盘左右箭头键控制</li>
                <li>🖼️ 点击底部缩略图跳转</li>
                <li>📱 支持触摸手势(移动端)</li>
            </ul>
        </div>
    </div>
</template>

<script setup>
import { ref } from "vue";
import { SwiperSimple } from "vue3-xm";

// 基础示例图片
const basicImages = ref([
    "https://picsum.photos/id/1/400/600",
    "https://picsum.photos/id/10/400/600",
    "https://picsum.photos/id/100/400/600",
    "https://picsum.photos/id/1000/400/600",
    "https://picsum.photos/id/1001/400/600",
]);
</script>

<style scoped>
.demo-container {
    padding: 24px;
    border: 1px solid #e0e0e0;
    border-radius: 12px;
    margin: 20px 0;
    background: #f8f9fa;
}

.swiper-wrapper {
    display: flex;
    justify-content: center;
    margin: 20px 0;
    background: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.info-panel {
    background: white;
    padding: 20px;
    border-radius: 8px;
    margin-top: 20px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.info-panel h4 {
    margin: 0 0 16px 0;
    color: #333;
    font-size: 18px;
    border-bottom: 2px solid #007bff;
    padding-bottom: 8px;
}

.info-panel ul {
    margin: 0;
    padding-left: 0;
    list-style: none;
}

.info-panel li {
    margin: 12px 0;
    padding: 8px 12px;
    background: #f8f9fa;
    border-radius: 6px;
    border-left: 4px solid #007bff;
    color: #666;
}
</style>

可配置显示选项演示

可配置显示选项演示

展示分页器和导航按钮的显示/隐藏配置。

当前配置

  • 分页器显示: 开启
  • 导航按钮显示: 开启
  • 🎯 无论何种配置,键盘控制始终有效
  • 🔄 自动播放和无限循环保持开启
查看代码
vue
<template>
    <div class="demo-container">
        <h3>可配置显示选项演示</h3>
        <p>展示分页器和导航按钮的显示/隐藏配置。</p>

        <div class="config-controls">
            <label>
                <input type="checkbox" v-model="showPagination" />
                显示分页器
            </label>
            <label>
                <input type="checkbox" v-model="showNavigation" />
                显示导航按钮
            </label>
        </div>

        <div class="swiper-wrapper">
            <SwiperSimple
                :img-list="configImages"
                :auto-play="true"
                :play-time="3"
                :infinite="true"
                :show-pagination="showPagination"
                :show-navigation="showNavigation"
                :keys-control="true"
            />
        </div>

        <div class="info-panel">
            <h4>当前配置</h4>
            <ul>
                <li>
                    分页器显示:
                    <span :class="showPagination ? 'enabled' : 'disabled'">{{ showPagination ? "开启" : "关闭" }}</span>
                </li>
                <li>
                    导航按钮显示:
                    <span :class="showNavigation ? 'enabled' : 'disabled'">{{ showNavigation ? "开启" : "关闭" }}</span>
                </li>
                <li>🎯 无论何种配置,键盘控制始终有效</li>
                <li>🔄 自动播放和无限循环保持开启</li>
            </ul>
        </div>
    </div>
</template>

<script setup>
import { ref } from "vue";
import { SwiperSimple } from "vue3-xm";

// 配置状态
const showPagination = ref(true);
const showNavigation = ref(true);

// 配置示例图片
const configImages = ref([
    "https://picsum.photos/id/1018/400/600",
    "https://picsum.photos/id/1025/400/600",
    "https://picsum.photos/id/1039/400/600",
    "https://picsum.photos/id/1043/400/600",
    "https://picsum.photos/id/1051/400/600",
]);
</script>

<style scoped>
.demo-container {
    padding: 24px;
    border: 1px solid #e0e0e0;
    border-radius: 12px;
    margin: 20px 0;
    background: #f8f9fa;
}

.config-controls {
    display: flex;
    gap: 20px;
    margin: 20px 0;
    padding: 16px;
    background: white;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.config-controls label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 500;
    color: #333;
    cursor: pointer;
}

.config-controls input[type="checkbox"] {
    width: 18px;
    height: 18px;
    cursor: pointer;
}

.swiper-wrapper {
    display: flex;
    justify-content: center;
    margin: 20px 0;
    background: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.info-panel {
    background: white;
    padding: 20px;
    border-radius: 8px;
    margin-top: 20px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.info-panel h4 {
    margin: 0 0 16px 0;
    color: #333;
    font-size: 18px;
    border-bottom: 2px solid #007bff;
    padding-bottom: 8px;
}

.info-panel ul {
    margin: 0;
    padding-left: 0;
    list-style: none;
}

.info-panel li {
    margin: 12px 0;
    padding: 8px 12px;
    background: #f8f9fa;
    border-radius: 6px;
    border-left: 4px solid #007bff;
    color: #666;
}

.enabled {
    color: #28a745;
    font-weight: bold;
}

.disabled {
    color: #dc3545;
    font-weight: bold;
}
</style>

高级配置演示

高级轮播图配置

这个示例展示了自动播放、无限循环、自定义按钮等高级功能。

当前配置

自动播放:开启
播放间隔:3秒
无限循环:开启
图片数量:8张

操作提示

🖱️ 点击自定义按钮控制轮播
⌨️ 键盘左右箭头键快速切换
🖼️ 点击底部缩略图精确跳转
⚙️ 实时调整播放设置
🔄 体验不同的循环模式
查看代码
vue
<template>
    <div class="demo-container">
        <h3>高级轮播图配置</h3>
        <p>这个示例展示了自动播放、无限循环、自定义按钮等高级功能。</p>

        <div class="controls">
            <button @click="toggleAutoPlay" :class="['control-btn', { active: isAutoPlay }]">
                {{ isAutoPlay ? "⏸️ 暂停自动播放" : "▶️ 开始自动播放" }}
            </button>
            <button @click="toggleInfinite" :class="['control-btn', { active: isInfinite }]">
                {{ isInfinite ? "🔄 关闭循环" : "🔄 开启循环" }}
            </button>
            <div class="speed-control">
                <label>播放速度:</label>
                <select v-model="playSpeed" @change="onSpeedChange">
                    <option value="1">1秒</option>
                    <option value="2">2秒</option>
                    <option value="3">3秒</option>
                    <option value="5">5秒</option>
                </select>
            </div>
        </div>

        <div class="swiper-wrapper">
            <SwiperSimple
                :img-list="advancedImages"
                :auto-play="isAutoPlay"
                :play-time="playSpeed"
                :infinite="isInfinite"
                :keys-control="true"
                ref="swiperRef"
            >
                <template #leftBtn>
                    <button class="custom-btn custom-btn-left" @click="prevSlide">⬅️ 上一张</button>
                </template>
                <template #rightBtn>
                    <button class="custom-btn custom-btn-right" @click="nextSlide">下一张 ➡️</button>
                </template>
            </SwiperSimple>
        </div>

        <div class="stats-panel">
            <div class="stat-item">
                <h4>当前配置</h4>
                <div class="config-list">
                    <div class="config-item">
                        <span class="config-label">自动播放:</span>
                        <span :class="['config-value', isAutoPlay ? 'enabled' : 'disabled']">
                            {{ isAutoPlay ? "开启" : "关闭" }}
                        </span>
                    </div>
                    <div class="config-item">
                        <span class="config-label">播放间隔:</span>
                        <span class="config-value">{{ playSpeed }}秒</span>
                    </div>
                    <div class="config-item">
                        <span class="config-label">无限循环:</span>
                        <span :class="['config-value', isInfinite ? 'enabled' : 'disabled']">
                            {{ isInfinite ? "开启" : "关闭" }}
                        </span>
                    </div>
                    <div class="config-item">
                        <span class="config-label">图片数量:</span>
                        <span class="config-value">{{ advancedImages.length }}张</span>
                    </div>
                </div>
            </div>

            <div class="stat-item">
                <h4>操作提示</h4>
                <div class="tips-list">
                    <div class="tip">🖱️ 点击自定义按钮控制轮播</div>
                    <div class="tip">⌨️ 键盘左右箭头键快速切换</div>
                    <div class="tip">🖼️ 点击底部缩略图精确跳转</div>
                    <div class="tip">⚙️ 实时调整播放设置</div>
                    <div class="tip">🔄 体验不同的循环模式</div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import { ref, nextTick } from "vue";
import { SwiperSimple } from "vue3-xm";

// 高级示例图片 - 更多图片
const advancedImages = ref([
    "https://picsum.photos/seed/demo2-1/400/600",
    "https://picsum.photos/seed/demo2-2/400/600",
    "https://picsum.photos/seed/demo2-3/400/600",
    "https://picsum.photos/seed/demo2-4/400/600",
    "https://picsum.photos/seed/demo2-5/400/600",
    "https://picsum.photos/seed/demo2-6/400/600",
    "https://picsum.photos/seed/demo2-7/400/600",
    "https://picsum.photos/seed/demo2-8/400/600",
]);

// 控制状态
const isAutoPlay = ref(true);
const isInfinite = ref(true);
const playSpeed = ref(3);
const swiperRef = ref(null);

// 切换自动播放
const toggleAutoPlay = () => {
    isAutoPlay.value = !isAutoPlay.value;
    // 这里可以调用组件的方法来动态控制播放状态
    nextTick(() => {
        if (swiperRef.value) {
            if (isAutoPlay.value) {
                swiperRef.value.play?.();
            } else {
                swiperRef.value.stop?.();
            }
        }
    });
};

// 切换无限循环
const toggleInfinite = () => {
    isInfinite.value = !isInfinite.value;
};

// 播放速度变化
const onSpeedChange = () => {
    // 重新启动自动播放以应用新的速度
    if (isAutoPlay.value && swiperRef.value) {
        swiperRef.value.stop?.();
        setTimeout(() => {
            swiperRef.value.play?.();
        }, 100);
    }
};

// 手动切换到下一张
const nextSlide = () => {
    if (swiperRef.value) {
        swiperRef.value.nextPage?.();
    }
};

// 手动切换到上一张
const prevSlide = () => {
    if (swiperRef.value) {
        swiperRef.value.prevPage?.();
    }
};
</script>

<style scoped>
.demo-container {
    padding: 24px;
    border: 1px solid #e0e0e0;
    border-radius: 12px;
    margin: 20px 0;
    background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
}

.controls {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 24px;
    padding: 16px;
    background: white;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.control-btn {
    padding: 10px 16px;
    border: 2px solid #007bff;
    border-radius: 6px;
    background: white;
    color: #007bff;
    cursor: pointer;
    font-size: 14px;
    transition: all 0.3s ease;
    font-weight: 500;
}

.control-btn:hover {
    background: #007bff;
    color: white;
}

.control-btn.active {
    background: #007bff;
    color: white;
}

.speed-control {
    display: flex;
    align-items: center;
    gap: 8px;
}

.speed-control label {
    font-weight: 500;
    color: #666;
}

.speed-control select {
    padding: 8px 12px;
    border: 1px solid #ddd;
    border-radius: 4px;
    background: white;
    cursor: pointer;
}

.swiper-wrapper {
    display: flex;
    justify-content: center;
    margin: 20px 0;
    background: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.custom-btn {
    background: rgba(0, 123, 255, 0.9);
    color: white;
    border: none;
    padding: 12px 16px;
    border-radius: 8px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    transition: all 0.3s ease;
    backdrop-filter: blur(10px);
    box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
}

.custom-btn:hover {
    background: rgba(0, 123, 255, 1);
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0, 123, 255, 0.4);
}

.stats-panel {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin-top: 20px;
}

.stat-item {
    background: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.stat-item h4 {
    margin: 0 0 16px 0;
    color: #333;
    font-size: 18px;
    border-bottom: 2px solid #007bff;
    padding-bottom: 8px;
}

.config-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin: 12px 0;
    padding: 8px 0;
    border-bottom: 1px solid #f0f0f0;
}

.config-label {
    font-weight: 500;
    color: #666;
}

.config-value {
    font-weight: 600;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 14px;
}

.config-value.enabled {
    background: #d4edda;
    color: #155724;
}

.config-value.disabled {
    background: #f8d7da;
    color: #721c24;
}

.tips-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.tip {
    padding: 10px 12px;
    background: #f8f9fa;
    border-radius: 6px;
    border-left: 4px solid #28a745;
    color: #666;
    font-size: 14px;
}

@media (max-width: 768px) {
    .controls {
        flex-direction: column;
    }

    .stats-panel {
        grid-template-columns: 1fr;
    }

    .speed-control {
        justify-content: space-between;
    }
}
</style>

API

Props

参数类型默认值说明
imgListArray<string>[]必需 图片地址数组
autoPlaybooleanfalse是否开启自动播放
playTimenumber | string2自动播放间隔时间(秒)
keysControlbooleantrue是否启用键盘控制(左右箭头键)
infinitebooleanfalse是否支持无限循环滚动
hoverPausebooleantrue鼠标悬浮时是否暂停自动播放(需开启自动播放)
showPaginationbooleantrue是否显示底部分页器(缩略图导航)
showNavigationbooleantrue是否显示左右导航按钮

Slots

插槽名说明
leftBtn自定义左侧导航按钮
rightBtn自定义右侧导航按钮

方法

方法名说明参数返回值
nextPage()切换到下一张图片--
prevPage()切换到上一张图片--
jumpByIndex(index)跳转到指定索引的图片index: number-
play()开始自动播放--
stop()停止自动播放--

Released under the MIT License.