在前端开发中,轮播组件是非常常见但又需要精心构造的 UI 块。本文将介绍如何利用 Swiper 框架结合原生的 DOM 操作,实现一个带有分页的轮播组件,并提供可复用的实现方式。
一、项目结构与目标
我们希望实现一个带有左右双引号和信息展示的测试评价轮播组件。该组件应支持:
- 将多条测试评价数据动态渲染为幻灯片(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效果可能没有正确设置所有幻灯片的透明度,导致多个幻灯片同时可见而产生堆叠
需要手动隐藏所有的卡片,并只展示当前激活的卡片
.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,我们能够轻松实现一个具有分页功能的轮播组件。这种方式不仅结构清晰,还便于扩展和维护。随着前端技术的不断发展,掌握这些基本技术点,有助于我们构建更复杂、功能更丰富的页面组件。