<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>平滑滚动轮播图</title>
<style>
.slider {
width: 500px;
margin: 40px auto;
text-align: center;
font-family: Arial, sans-serif;
}
.slider-window {
width: 100%;
overflow: hidden;
}
.slider-track {
display: flex;
transition: transform 0.6s ease; /* 平滑滚动动画 */
}
.slider-track img {
width: 500px;
height: 280px;
object-fit: cover;
flex-shrink: 0;
}
.indicators {
margin-top: 10px;
}
.indicators span {
display: inline-block;
margin: 0 4px;
padding: 4px 8px;
border: 1px solid #333;
cursor: pointer;
font-size: 14px;
user-select: none;
}
.indicators .active {
background: #333;
color: #fff;
}
</style>
</head>
<body>
<div class="slider">
<div class="slider-window">
<div class="slider-track" id="slider-track">
<!-- JS 动态插入图片 -->
</div>
</div>
<div class="indicators" id="indicators">
<!-- JS 动态插入 1 2 3 4 5 -->
</div>
</div>
<script>
const images = [
'../img/z1.jpg',
'../img/z2.jpg',
'../img/z3.jpg',
'../img/z4.jpg',
'../img/z5.jpg',
];
const track = document.getElementById('slider-track');
const indicatorsBox = document.getElementById('indicators');
// 动态创建图片
images.forEach(src => {
const img = document.createElement('img');
img.src = src;
track.appendChild(img);
});
// 动态创建指示器 1、2、3、4、5
const indicators = [];
images.forEach((_, index) => {
const span = document.createElement('span');
span.textContent = index + 1;
if (index === 0) span.classList.add('active');
span.dataset.index = index;
indicatorsBox.appendChild(span);
indicators.push(span);
});
let current = 0;
const slideWidth = 500; // 和 .slider 的宽度一致
function goToSlide(index) {
current = index;
const offset = -current * slideWidth;
track.style.transform = `translateX(${offset}px)`;
indicators.forEach(i => i.classList.remove('active'));
indicators[current].classList.add('active');
}
// 指示器点击
indicators.forEach(span => {
span.addEventListener('click', () => {
const index = Number(span.dataset.index);
goToSlide(index);
});
});
// 自动轮播(可选,想关掉就注释掉这一段)
setInterval(() => {
const next = (current + 1) % images.length;
goToSlide(next);
}, 3000);
</script>
</body>
</html>
HTML 结构部分
<!DOCTYPE html>
- 声明文档类型,告诉浏览器这是一个 HTML5 文档。
<html lang="zh-CN">
<html>根标签,包住整页内容。lang="zh-CN"声明当前页面语言是简体中文,方便搜索引擎和屏幕阅读器。
<head>
<head>头部,放页面配置(编码、标题、样式等),不直接显示在页面中。
<meta charset="UTF-8">
- 设置页面的字符编码为 UTF-8,保证中文不会出现乱码。
<title>平滑滚动轮播图</title>
- 设置浏览器标签栏上显示的标题文字。
<style>
- 内联样式标签,里面写 CSS。
CSS 样式部分
.slider {
width: 500px;
margin: 40px auto;
text-align: center;
font-family: Arial, sans-serif;
}
.slider:轮播组件的最外层容器。width: 500px;:整体宽度 500 像素。margin: 40px auto;:上下外边距 40px,左右自动居中,所以整个模块居中显示。text-align: center;:内部文本居中(主要影响下面指示器的文字)。font-family: Arial, sans-serif;:设置字体为 Arial 或其他无衬线字体。
.slider-window {
width: 100%;
overflow: hidden;
}
.slider-window:可视窗口容器,限制显示区域。width: 100%;:宽度占满父容器(也就是 500px)。overflow: hidden;:把超出这个区域的内容隐藏掉,这样左右滑动时只看到当前这一屏。
.slider-track {
display: flex;
transition: transform 0.6s ease; /* 平滑滚动动画 */
}
.slider-track:所有图片所在的滑动轨道。display: flex;:让里面的图片水平排成一行。transition: transform 0.6s ease;:当transform变化时,使用 0.6 秒的过渡动画,效果是平滑滚动。
.slider-track img {
width: 500px;
height: 280px;
object-fit: cover;
flex-shrink: 0;
}
.slider-track img:轨道里的每一张图片。width: 500px;:每张图片宽度与轮播宽度一致。height: 280px;:统一高度 280 像素。object-fit: cover;:按比例裁剪填满盒子,多余部分裁掉,不会变形。flex-shrink: 0;:在 flex 布局中禁止图片被压缩,保证每张图固定 500px 宽。
.indicators {
margin-top: 10px;
}
.indicators:下面装 1、2、3、4、5 的容器。margin-top: 10px;:与轮播图之间留出 10px 间距。
.indicators span {
display: inline-block;
margin: 0 4px;
padding: 4px 8px;
border: 1px solid #333;
cursor: pointer;
font-size: 14px;
user-select: none;
}
.indicators span:每个数字按钮。display: inline-block;:既可以像行内元素一样排一行,又可以设置宽高/内边距。margin: 0 4px;:左右间距 4px,让数字之间不要紧贴。padding: 4px 8px;:内边距,让按钮看起来有点块感。border: 1px solid #333;:边框为深灰色细线。cursor: pointer;:鼠标移上去变成小手,提示可点击。font-size: 14px;:调整字体大小。user-select: none;:禁止选中文字,点击更干净。
.indicators .active {
background: #333;
color: #fff;
}
.indicators .active:当前选中的按钮增加active类后使用的样式。background: #333;:背景深灰色。color: #fff;:文字变白色,看起来被“选中”。
</style>
</head>
<body>
- 结束
<style>和<head>,开始<body>页面主体内容。
轮播 HTML 结构
<div class="slider">
- 创建轮播组件最外层容器,使用前面定义的
.slider样式。
<div class="slider-window">
- 可视窗口容器,相当于一个“窗口框”,只让你看到当前的那张图。
<div class="slider-track" id="slider-track">
<!-- JS 动态插入图片 -->
</div>
class="slider-track":轨道容器,里面本来没有图片,后面用 JS 动态插入。id="slider-track":给它一个 id,方便 JS 用getElementById找到。- 中间注释说明:这里不在 HTML 里写
<img>,全部由 JS 创建。
</div>
<div class="indicators" id="indicators">
<!-- JS 动态插入 1 2 3 4 5 -->
</div>
</div>
- 结束
slider-window。 <div class="indicators" id="indicators">:指示器容器,下面数字按钮会由 JS 动态创建。- 注释说明:JS 生成 1、2、3、4、5。
- 结束外层
.slider容器。
JS 脚本部分
<script>
- 开始写 JavaScript 脚本。
const images = [
'../img/z1.jpg',
'../img/z2.jpg',
'../img/z3.jpg',
'../img/z4.jpg',
'../img/z5.jpg',
];
- 定义一个常量
images,是一个数组,里面存放 5 张轮播图的路径。 - 每一行都是一个字符串,对应一张图片的位置。
const track = document.getElementById('slider-track');
- 从 DOM 中获取 id 为
slider-track的元素,也就是图片轨道容器。 - 赋值给常量
track,后面要往里塞<img>,并控制它的transform。
const indicatorsBox = document.getElementById('indicators');
- 获取 id 为
indicators的元素,也就是放 1/2/3/4/5 的容器。 - 赋值给
indicatorsBox,后面会往里面添加<span>标签。
动态创建图片
// 动态创建图片
images.forEach(src => {
const img = document.createElement('img');
img.src = src;
track.appendChild(img);
});
逐行解释:
images.forEach(src => { ... });- 遍历
images数组,每次循环把当前项赋给src(图片路径)。 forEach是数组的遍历方法,不返回新数组,只执行回调。
- 遍历
const img = document.createElement('img');- 每次循环创建一个新的
<img>元素。 document.createElement('img')用 JS 在内存中生成一个 img 标签。
- 每次循环创建一个新的
img.src = src;- 设置图片的
src属性为当前这张图片路径。 - 这样
<img>就知道要显示哪张图。
- 设置图片的
track.appendChild(img);- 把这个新建的
<img>插入到track容器的最后面。 - 最终形成一个横向排布的图片队列。
- 把这个新建的
动态创建指示器(1、2、3、4、5)
// 动态创建指示器 1、2、3、4、5
const indicators = [];
- 注释说明这段是创建下面的数字按钮。
const indicators = [];创建一个空数组,用来存所有创建好的<span>指示器,后面需要操作它们的样式和事件。
images.forEach((_, index) => {
const span = document.createElement('span');
span.textContent = index + 1;
if (index === 0) span.classList.add('active');
span.dataset.index = index;
indicatorsBox.appendChild(span);
indicators.push(span);
});
逐行解释:
images.forEach((_, index) => { ... });- 再次遍历
images数组,这次我们只需要索引index,所以第一个参数写_表示“我不关心这个值”(图片路径)。 index从 0 到 4,对应第 1 到第 5 张图。
- 再次遍历
const span = document.createElement('span');- 创建一个新的
<span>元素,作为一个数字按钮。
- 创建一个新的
span.textContent = index + 1;- 设置 span 的文本内容为
index + 1,也就是 1、2、3、4、5。 - 注意 index 从 0 起,所以要加 1 给用户看。
- 设置 span 的文本内容为
if (index === 0) span.classList.add('active');- 如果是第一个按钮(index 为 0),给它加上
active类。 - 这样初始状态下第一个按钮是高亮的,对应第一张图默认显示。
- 如果是第一个按钮(index 为 0),给它加上
span.dataset.index = index;- 给 span 设置一个自定义属性
data-index。 - 写成 JS 是
dataset.index,写到 HTML 就是data-index="0"这样。 - 后面点击的时候,会通过这个 index 找到要切换到第几张图片。
- 给 span 设置一个自定义属性
indicatorsBox.appendChild(span);- 把这个 span 挂到页面中的
indicatorsBox容器里。
- 把这个 span 挂到页面中的
indicators.push(span);- 把这个 span 保存到
indicators数组中,之后切换时需要统一操作所有按钮的样式。
- 把这个 span 保存到
当前索引与每张幻灯片宽度
let current = 0;
- 定义变量
current,记录当前显示的是第几张图片。 - 初始设为
0,表示第一张(因为数组下标从 0 开始)。
const slideWidth = 500; // 和 .slider 的宽度一致
- 定义常量
slideWidth,表示每一张幻灯片的宽度。 - 填写的是 500,与 CSS 中
.slider和.slider-track img的宽度一致。 - 用来计算轨道要向左移动多少像素。
切换图片的核心函数
function goToSlide(index) {
current = index;
const offset = -current * slideWidth;
track.style.transform = `translateX(${offset}px)`;
indicators.forEach(i => i.classList.remove('active'));
indicators[current].classList.add('active');
}
逐行解释:
function goToSlide(index) { ... }- 定义一个函数,用来跳转到指定序号的图片。
- 参数
index是目标图片的下标(0~4)。
current = index;- 更新当前索引
current为要跳转到的这一张。
- 更新当前索引
const offset = -current * slideWidth;- 计算轨道需要平移的距离。
- 比如当前是第 2 张(index=1),offset = -1 * 500 = -500 像素,表示整体左移 500px,让第二张对齐窗口。
track.style.transform =translateX(${offset}px);- 设置轨道的 CSS
transform属性为平移。 - 利用 CSS 里写好的
transition: transform 0.6s ease;,会产生平滑动画。
- 设置轨道的 CSS
indicators.forEach(i => i.classList.remove('active'));- 遍历所有按钮,把它们的
active类全部移除,先清空高亮状态。
- 遍历所有按钮,把它们的
indicators[current].classList.add('active');- 再给当前这一项(新的 current)添加
active类,表示现在这一张是选中状态,对应数字高亮。
- 再给当前这一项(新的 current)添加
给指示器添加点击事件
// 指示器点击
indicators.forEach(span => {
span.addEventListener('click', () => {
const index = Number(span.dataset.index);
goToSlide(index);
});
});
逐行解释:
- 注释:说明下面代码是处理“点击下面1、2、3、4、5”的逻辑。
indicators.forEach(span => { ... });- 遍历存好的所有 span 按钮。
span.addEventListener('click', () => { ... });- 给每个按钮注册一个点击事件监听器。
- 当用户点击某个数字时,会触发回调函数。
const index = Number(span.dataset.index);- 从该按钮的自定义属性
data-index里取出对应的下标。 span.dataset.index返回字符串,需要用Number()转成数字。
- 从该按钮的自定义属性
goToSlide(index);- 调用前面写好的切换函数,切到对应的图片。
自动轮播部分(定时切换)
// 自动轮播(可选,想关掉就注释掉这一段)
setInterval(() => {
const next = (current + 1) % images.length;
goToSlide(next);
}, 3000);
逐行解释:
- 注释说明:这是自动轮播,如果不想自动切换,可以整段注释掉。
setInterval(() => { ... }, 3000);- 设置一个定时器,每隔 3000 毫秒(3 秒)执行一次回调函数。
- 实现“每 3 秒自动切换到下一张”。
const next = (current + 1) % images.length;- 计算下一张图片的下标:
current + 1:当前索引加 1。% images.length:模运算,让它超过最后一张时从 0 重新开始。- 比如
current是 4(最后一张),(4+1) % 5 = 0,回到第一张。
- 计算下一张图片的下标:
goToSlide(next);- 调用切换函数,切换到下一张图片。
</script>
</body>
</html>
- 结束
<script>。 - 结束
<body>和<html>,页面结构结束。