使用 Swiper 实现响应式分页轮播组件:实现思路与Demo

130 阅读5分钟

在前端开发中,轮播组件是非常常见但又需要精心构造的 UI 块。本文将介绍如何利用 Swiper 框架结合原生的 DOM 操作,实现一个带有分页的轮播组件,并提供可复用的实现方式。

2025-09-1313-19-28-ezgif.com-video-to-gif-converter.gif

一、项目结构与目标

我们希望实现一个带有左右双引号和信息展示的测试评价轮播组件。该组件应支持:

  • 将多条测试评价数据动态渲染为幻灯片(cards);
  • 使用 Swiper 实现轮播(横向滑动);
  • 配备分页控制(点击分页点切换幻灯片);
  • 响应式设计(适配不同屏幕尺寸)。

二、实现思路与关键技术点

1. 使用 Swiper 创建轮播基础结构

Swiper 是一个基于现代浏览器的轻量级响应式轮播库,功能强大且使用简单。我们通过以下步骤引入 Swiper:

  • 链接引入库的 CSS 文件;
  • 引入库的 JS 文件;
  • 创建基础结构(<div class="swiper-container">);
  • 使用 Swiper 初始化配置,设置分页等关键功能。

2. 创建幻灯片内容内容写入 DOM

我们通过 JavaScript 动态生成每张幻灯片的内容:

  • 使用 document.createElement 创建元素;
  • 使用 appendChild 添加子元素到幻灯片中;
  • 使用 innerHTML 设置动态内容,如评论、人名、公司信息等。

注:在实际应用中,评论数据从后端获取,本文模拟数据生成逻辑。

3. 实现响应式布局

Swiper 提供了响应式配置的 API,可以设置不同屏幕尺寸下的展示方式,例如滑动的张数(slidesPerView)以及间距(spaceBetween)。

三、核心代码实现

以下展示了我们使用 HTML、CSS 和 JavaScript 在页面中动态构建轮播组件。

1. HTML 结构(模板)

<main class="container">
    <section class="swiper-container">
        <div class="swiper-wrapper" id="testimonialWrapper"></div>
        <div class="swiper-pagination"></div>
    </section>
</main>

2. CSS 样式

@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap");
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: "Poppins", sans-serif;
}
h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    font-style: normal;
    color: #333333;
}
body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: white;
}
.container {
    max-width: 1200px;
    padding: 20px;
    overflow: hidden;
    width: 100%;
}
.swiper-container {
    padding-top: 50px;
    padding-bottom: 50px;
}
.testimonial-item {
    padding: 30px;
    margin-bottom: 10px;
}
.testimonial-content {
    position: relative;
    padding: 30px 20px 20px 60px;
    background-color: #fff;
    border-radius: 8px;
    border: 2px solid #e5e5e5;
    transition: all .25s ease-in-out;
}
.testimonial-picture {
    position: absolute;
    top: -30px;
    left: -30px;
    width: 80px;
    height: 80px;
}
.testimonial-picture img {
    border-radius: 50%;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.testimonial-text p {
    font-style: italic;
    font-size: 14px;
    color: #666;
    margin: 0 0 10px;
}
.testimonial-author-info {
    margin-top: 15px;
}
.testimonial-author {
    margin: 0 0 2px;
    font-size: 0.9em;
}
.testimonial-firm {
    margin: 0;
    font-size: 0.8em;
    color: #bbb;
}
.testimonial-icon {
    position: absolute;
    left: 20px;
    bottom: 46px;
    color: #e5e5e5;
    font-size: 20px;
}
.testimonial-icon-big {
    position: absolute;
    right: -24px;
    bottom: -24px;
    color: #f5f5f5;
    font-size: 44px;
    z-index: -1;
}
/* 分页样式 */
.swiper-pagination {
    position: relative;
    top: 20px;
}
.swiper-pagination-bullet {
    width: 20px;
    height: 4px;
    border-radius: 2px;
    background: #ccc;
    opacity: 1;
    margin: 0 5px;
    outline: none;
}
.swiper-pagination-bullet-active {
    background: #007ced;
}

3. JavaScript 逻辑(模拟数据 + 渲染幻灯片)

// 模拟一个工程数据接口
function fetchTestimonials() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve([
                {
                    image: "//example.com/images/1.jpg",
                    text: "Donec eu est vel metus consequat volutpat. Nunc aliquet euismod mauris, a feugiat urna ullamcorper non.",
                    author: "用户A",
                    firm: "公司A"
                },
                {
                    image: "//example.com/images/2.jpg",
                    text: "Nam tempor commodo mi id sodales. Aenean sit amet nibh nec sapien consequat porta a sit amet diam.",
                    author: "用户B",
                    firm: "公司B"
                },
                {
                    image: "//example.com/images/3.jpg",
                    text: "Donec eu est vel metus consequat volutpat. Nunc aliquet euismod mauris, a feugiat urna ullamcorper non.",
                    author: "用户C",
                    firm: "公司C"
                },
                {
                    image: "//example.com/images/4.jpg",
                    text: "Nam tempor commodo mi id sodales. Aenean sit amet nibh nec sapien consequat porta a sit amet diam.",
                    author: "用户D",
                    firm: "公司D"
                }
            ]);
        }, 1000);
    });
}
// 动态加载并生成幻灯片
async function loadTestimonials() {
    const testimonials = await fetchTestimonials();
    const wrapper = document.getElementById('testimonialWrapper');
    testimonials.forEach(testimonial => {
        const slide = document.createElement('div');
        slide.className = 'swiper-slide';
        const item = document.createElement('div');
        item.className = 'testimonial-item';
        const content = document.createElement('div');
        content.className = 'testimonial-content';
        const picture = document.createElement('div');
        picture.className = 'testimonial-picture';
        const img = document.createElement('img');
        img.src = testimonial.image;
        img.alt = testimonial.author;
        picture.appendChild(img);
        const text = document.createElement('div');
        text.className = 'testimonial-text';
        text.innerHTML = `<p>${testimonial.text}</p>`;
        const authorInfo = document.createElement('div');
        authorInfo.className = 'testimonial-author-info';
        authorInfo.innerHTML = `
            <h5 class="testimonial-author">${testimonial.author}</h5>
            <p class="testimonial-firm">${testimonial.firm}</p>
        `;
        const iconLeft = document.createElement('div');
        iconLeft.className = 'testimonial-icon';
        iconLeft.innerHTML = '<i class="fa fa-quote-left"></i>';
        const iconRight = document.createElement('div');
        iconRight.className = 'testimonial-icon-big';
        iconRight.innerHTML = '<i class="fa fa-quote-right"></i>';
        content.appendChild(picture);
        content.appendChild(text);
        content.appendChild(authorInfo);
        content.appendChild(iconLeft);
        content.appendChild(iconRight);
        item.appendChild(content);
        slide.appendChild(item);
        wrapper.appendChild(slide);
    });
    // 初始化 Swiper
    var swiper = new Swiper('.swiper-container', {
        direction: 'horizontal',
        // 将当前幻灯片居中显示
        centeredSlides: false,
        grabCursor: true,
        pagination: {
            el: '.swiper-pagination',
            clickable: true,
            dynamicBullets: true
        },
        breakpoints: {
            627: {
                slidesPerView: 2,
                spaceBetween: 20,
            },
            320: {
                slidesPerView: 1,
                spaceBetween: 20,
            }
        }
    });
}
// 页面加载后初始化轮播
window.addEventListener('load', loadTestimonials);

四、关键 DOM 操作方法解析

1. createElement

用于创建新的 HTML 元素对象,是动态构建界面的基础。

<JS>
const slide = document.createElement('div');
const item = document.createElement('div');

2. appendChild

将创建的元素附加到其父节点下,用于构建 DOM 树。

<JS>
slide.appendChild(item);

3. innerHTML

设置 HTML 内容,适合需要动态填充的元素。但需注意安全风险(如 XSS),应优先使用 textContent

<JS>
text.innerHTML = `<p>${testimonial.text}</p>`;

4. className

设置元素的类名,方便 CSS 样式管理和操作。

<JS>
slide.className = 'swiper-slide';

五、经验总结与最佳实践

  • 使用 Swiper 前,应该确保已添加其 CSS 和 JS 库。
  • innerHTML 在某些场景下非常重要,但务必注意用法安全。
  • 最小化 HTML 的结构,将渲染尽量交给 JS 完成,提高模块化和可维护性。
  • 响应式配置使用 breakpoints 属性进行适配,非常灵活。
  • 在创建CSS类名或元素时,使用 className 和 classList 更加安全和推荐。

六、拓展:使用Swiper实现淡出淡入效果

Swiper的fade效果需要手动控制透明度

默认情况下,Swiper的fade效果可能没有正确设置所有幻灯片的透明度,导致多个幻灯片同时可见而产生堆叠

image.png

需要手动隐藏所有的卡片,并只展示当前激活的卡片

.swiper-slide {
    opacity: 0 !important; /* 强制所有幻灯片隐藏 */
    transition: opacity 0.2s ease-out !important; /* 添加淡入淡出动画 */
}
.swiper-slide-active,
.swiper-slide-duplicate-active {
    opacity: 1 !important; /* 只有活动幻灯片显示 */
}

七、结语

通过结合 Swiper 和 DOM API,我们能够轻松实现一个具有分页功能的轮播组件。这种方式不仅结构清晰,还便于扩展和维护。随着前端技术的不断发展,掌握这些基本技术点,有助于我们构建更复杂、功能更丰富的页面组件。