第一部分:轮播图HTML/CSS基础实现
1.1 核心设计思想:胶卷模型
⭐ 老师强调:轮播图的本质是"窗口+胶卷"模型。整个ul就像一长条电影胶卷,每个li(包含图片)就像胶卷里的一帧画面。通过父容器的overflow:hidden隐藏超出部分,只暴露一个"窗口",再控制胶卷的左右移动来切换显示不同图片。
┌─────────────────────────────────────────────────────────────┐
│ 胶卷(imgbox,所有图片排成一行) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 图片1 │ │ 图片2 │ │ 图片3 │ │
│ │ 800×350 │ │ 800×350 │ │ 800×350 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ ▲ │
│ │ │
│ 窗口(container,只显示当前一张) │
│ ┌─────────┐ │
│ │ 图片1 │ ← 可见区域 │
│ └─────────┘ │
└─────────────────────────────────────────────────────────────┘
1.2 HTML 结构
<div class="container"> <!– 窗口:固定大小,overflow:hidden –>
<ul class="imgbox"> <!– 胶卷:所有图片排成一行 –>
<li><img src="imgtu1.png"></li>
<li><img src="imgtu2.jpg"></li>
<li><img src="imgtu3.png"></li>
</ul>
<ul class="btnbox"> <!– 控制按钮 –>
<li><img src="imgic_previous.png" class="left"></li>
<li><img src="imgic_next.png" class="right"></li>
</ul>
</div>
结构说明:
| .container | 窗口 | 固定宽高,overflow:hidden,position:relative |
| .imgbox | 胶卷 | 宽度=图片数×单张宽度,position:absolute,display:flex |
| .imgbox li | 单帧 | 每张图片的容器 |
| .btnbox | 控制器 | 绝对定位覆盖在窗口上,左右分布 |
1.3 CSS 样式
/* 重置 */
* {
padding: 0;
margin: 0;
}
/* 窗口:固定尺寸,隐藏溢出,相对定位作为参照 */
.container {
width: 800px;
height: 350px;
background: skyblue;
margin: 150px auto;
position: relative; /* 为子元素提供定位参照 */
overflow: hidden; /* 关键:隐藏超出部分 */
}
/* 胶卷:三张图片排成一行,绝对定位便于平移 */
.imgbox {
width: 2400px; /* 3张 × 800px */
height: 350px;
background: yellow;
display: flex; /* 弹性盒子让li横向排列 */
position: absolute; /* 相对父容器定位 */
left: -800px; /* 初始显示第二张(演示效果) */
}
/* 列表项:去除默认样式 */
.imgbox li {
list-style: none;
}
/* 图片:统一尺寸,cover填充 */
.imgbox li img {
width: 800px;
height: 350px;
object-fit: cover;
}
/* 按钮容器:绝对定位覆盖在图片上层 */
.btnbox {
position: absolute;
width: 800px;
height: 50px;
top: 150px; /* 垂直居中 (350-50)/2=150 */
display: flex;
justify-content: space-between; /* 左右分布 */
}
.btnbox li {
list-style: none;
}
.btnbox li img {
width: 50px;
height: 50px;
}
1.4 关键CSS属性解析
| overflow: hidden | 隐藏溢出内容 | 形成"窗口",只显示胶卷的一部分 |
| position: relative(父容器) | 作为子元素定位参照 | 子元素absolute相对父容器定位 |
| position: absolute(胶卷) | 脱离文档流,便于平移 | 通过left属性控制显示位置 |
| display: flex(胶卷) | 让li横向排列 | 替代float,更简洁 |
| object-fit: cover | 图片填充容器 | 保持比例,裁剪溢出部分 |
⭐ 老师强调:当元素设置了absolute定位后,会脱离文档流,margin:auto居中就会失效,需要通过left/top手动计算位置。
1.5 位置与显示关系
| 0 | 图片1(第一张) |
| -800px | 图片2(第二张) |
| -1600px | 图片3(第三张) |
第二部分:JavaScript轮播交互实现
2.1 核心切换函数
⭐ 老师强调:将切换逻辑封装成一个通用函数,通过传入不同参数控制切换方向和步长,避免代码重复。
window.onload = function() {
// 获取胶卷元素
var imgbox = document.querySelector(".imgbox");
// 初始化位置(解决CSS设置left后JS无法获取的问题)
imgbox.style.left = "0";
// ⭐ 通用切换函数:接收偏移量(正负值)
var change = function(grp) {
// 获取当前位置并转为数字
var newPosition = parseInt(imgbox.style.left) + grp;
// 边界控制:超出范围则循环
if (newPosition < -1600) {
newPosition = 0; // 最后一张→第一张
} else if (newPosition > 0) {
newPosition = -1600; // 第一张→最后一张
}
// 应用新位置
imgbox.style.left = newPosition + "px";
};
// … 后续功能
};
2.2 位置初始化的必要性
⭐ 老师强调:CSS设置的left属性只影响渲染效果,不会真正写入DOM元素的style属性。通过element.style.left获取时会得到空值。因此需要在JS中显式初始化imgbox.style.left = "0"。
/* CSS中设置left,JS无法读取 */
.imgbox {
left: -800px; /* 渲染生效,但 element.style.left 为空 */
}
// ✅ 正确做法:JS中显式初始化
imgbox.style.left = "0"; // 这样后续才能读取和计算
⭐ 老师强调:这就像化妆能改变人的外观,但不会改变人的本质特征。CSS负责样式渲染,JavaScript操作DOM属性,两者是不同的层面。
2.3 parseInt() 的必要性
// ❌ 错误:直接对带单位的字符串做加法
var newPosition = imgbox.style.left + grp; // "0" + (-800) = "0-800"
// ✅ 正确:先转为数字再运算
var newPosition = parseInt(imgbox.style.left) + grp; // 0 + (-800) = -800
⭐ 老师强调:parseInt()能把字符串"0px"或"-800px"开头的数字部分提取为整数,这样才能进行数学运算。带单位的数据必须先转换才能正确参与计算。
2.4 自动轮播(setInterval)
// 每4秒自动切换到下一张
setInterval(function() {
change(-800); // 向左移动800px(显示下一张)
}, 4000);
2.5 手动切换(按钮事件)
// 上一张:向右移动
var leftBtn = document.querySelector(".left");
leftBtn.onclick = function() {
change(800); // 正数:向右移动(显示上一张)
};
// 下一张:向左移动
var rightBtn = document.querySelector(".right");
rightBtn.onclick = function() {
change(-800); // 负数:向左移动(显示下一张)
};
2.6 完整轮播图JS代码
window.onload = function() {
var imgbox = document.querySelector(".imgbox");
imgbox.style.left = "0";
// 通用切换函数
var change = function(grp) {
var newPosition = parseInt(imgbox.style.left) + grp;
// 边界循环
if (newPosition < -1600) {
newPosition = 0;
} else if (newPosition > 0) {
newPosition = -1600;
}
imgbox.style.left = newPosition + "px";
};
// 自动轮播(每4秒切换)
setInterval(function() {
change(-800);
}, 4000);
// 上一张
var leftBtn = document.querySelector(".left");
leftBtn.onclick = function() {
change(800);
};
// 下一张
var rightBtn = document.querySelector(".right");
rightBtn.onclick = function() {
change(-800);
};
};
第三部分:代码复用与优化
3.1 为什么要合并代码
⭐ 老师强调:自动轮播和手动点击切换本质上使用的是相同的逻辑——都是通过改变left值切换图片。代码重复会导致两个问题:一是冗余(同样的逻辑写两遍),二是维护困难(未来修改时需要同步改动两处)。
优化前(代码重复):
// 自动轮播
setInterval(function() {
var pos = parseInt(imgbox.style.left) – 800;
if (pos < -1600) pos = 0;
imgbox.style.left = pos + "px";
}, 4000);
// 上一张
leftBtn.onclick = function() {
var pos = parseInt(imgbox.style.left) + 800;
if (pos > 0) pos = -1600;
imgbox.style.left = pos + "px";
};
// 下一张
rightBtn.onclick = function() {
var pos = parseInt(imgbox.style.left) – 800;
if (pos < -1600) pos = 0;
imgbox.style.left = pos + "px";
};
优化后(提取公共函数):
// 一个函数处理所有切换逻辑
var change = function(grp) {
var newPosition = parseInt(imgbox.style.left) + grp;
if (newPosition < -1600) newPosition = 0;
else if (newPosition > 0) newPosition = -1600;
imgbox.style.left = newPosition + "px";
};
// 三处调用同一函数,传入不同参数
setInterval(function() { change(-800); }, 4000);
leftBtn.onclick = function() { change(800); };
rightBtn.onclick = function() { change(-800); };
3.2 事件绑定的正确方式
⭐ 老师强调:事件绑定中,不加括号的函数名代表函数本身,加了括号的函数调用会立即执行并返回结果。
// ❌ 错误:change(-800) 立即执行,返回值(undefined)绑定给onclick
leftBtn.onclick = change(-800);
// ✅ 正确:用匿名函数包裹,点击时才执行
leftBtn.onclick = function() {
change(-800);
};
// ✅ 也可以:如果不需要传参,直接传函数名
rightBtn.onclick = change; // 但此时无法传参
核心区别:
| change | 函数引用(函数本身) | 事件触发时执行 |
| change() | 函数调用(立即执行) | 立即执行,返回结果 |
第四部分:任意页切换功能
4.1 核心思路
⭐ 老师强调:任意页切换的核心是直接跳转到目标页对应的left值。提前预设好每个页面对应的位置参数(0、-800、-1600),点击页码按钮时直接将胶卷移动到对应位置。这种方法直观简单,适合页面数量固定的场景。
页面对应关系:
| 第1页 | 0 | 显示第一张图片 |
| 第2页 | -800px | 显示第二张图片 |
| 第3页 | -1600px | 显示第三张图片 |
⭐ 老师强调:这种方式的优点是代码直观、逻辑清晰,每个按钮绑定固定的位置值。缺点是如果图片数量变化需要手动调整,但适用于固定页数的轮播场景。
4.2 任意页切换代码(直接赋值法)
window.onload = function() {
var imgbox = document.querySelector(".imgbox");
imgbox.style.left = "0";
// 获取三个页码按钮
var first = document.querySelector(".first");
var second = document.querySelector(".second");
var third = document.querySelector(".third");
// 点击第1页 → 跳到 left: 0
first.onclick = function() {
imgbox.style.left = "0px";
};
// 点击第2页 → 跳到 left: -800px
second.onclick = function() {
imgbox.style.left = "-800px";
};
// 点击第3页 → 跳到 left: -1600px
third.onclick = function() {
imgbox.style.left = "-1600px";
};
};
4.3 结合自动轮播与手动切换(完整代码)
window.onload = function() {
var imgbox = document.querySelector(".imgbox");
imgbox.style.left = "0";
// 通用切换函数(支持边界循环)
var change = function(grp) {
var newPosition = parseInt(imgbox.style.left) + grp;
if (newPosition < -1600) newPosition = 0;
else if (newPosition > 0) newPosition = -1600;
imgbox.style.left = newPosition + "px";
};
// 自动轮播
setInterval(function() {
change(-800);
}, 4000);
// 上一张 / 下一张
document.querySelector(".left").onclick = function() {
change(800);
};
document.querySelector(".right").onclick = function() {
change(-800);
};
// 任意页跳转(直接设置left值)
document.querySelector(".first").onclick = function() {
imgbox.style.left = "0px";
};
document.querySelector(".second").onclick = function() {
imgbox.style.left = "-800px";
};
document.querySelector(".third").onclick = function() {
imgbox.style.left = "-1600px";
};
};
4.4 任意页切换HTML示例
<!– 页码按钮 –>
<div class="page-btns">
<button class="first">1</button>
<button class="second">2</button>
<button class="third">3</button>
</div>
4.5 两种实现方式对比
| 实现方式 | 每个按钮固定left值 | 通过页码差计算偏移量 |
| 代码量 | 每个按钮单独写 | 一套逻辑处理所有 |
| 扩展性 | 页数变化需手动增删 | 只需修改总页数变量 |
| 可读性 | 直观易理解 | 需要理解计算逻辑 |
| 适用场景 | 固定页数(3页) | 页数可变的通用场景 |
⭐ 老师强调:实现思路不唯一,就像做增删改查这样的基础功能也可能有多种实现方式。直接赋值法简单直观,适合固定页数的轮播;页码差计算法更通用,适合页数可变的场景。初学者可以先从直接赋值法入手,理解后再尝试更通用的方案。
附录一:轮播图完整代码
HTML (轮播图.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轮播图</title>
<script src="js/轮播图.js"></script>
<link rel="stylesheet" href="css/轮播图.css">
</head>
<body>
<div class="container">
<ul class="imgbox">
<li><img src="imgtu1.png" alt=""></li>
<li><img src="imgtu2.jpg" alt=""></li>
<li><img src="imgtu3.png" alt=""></li>
</ul>
<ul class="btnbox">
<li><img src="imgic_previous.png" class="left"></li>
<li><img src="imgic_next.png" class="right"></li>
</ul>
<div class="page-btns">
<button class="first">1</button>
<button class="second">2</button>
<button class="third">3</button>
</div>
</div>
</body>
</html>
CSS (轮播图.css)
* { padding: 0; margin: 0; }
.container {
width: 800px;
height: 350px;
margin: 150px auto;
position: relative;
overflow: hidden;
}
.imgbox {
width: 2400px;
height: 350px;
display: flex;
position: absolute;
left: 0;
}
.imgbox li {
list-style: none;
}
.imgbox li img {
width: 800px;
height: 350px;
object-fit: cover;
}
.btnbox {
position: absolute;
width: 800px;
height: 50px;
top: 150px;
display: flex;
justify-content: space-between;
}
.btnbox li {
list-style: none;
}
.btnbox li img {
width: 50px;
height: 50px;
cursor: pointer;
}
.page-btns {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 20px;
}
.page-btns button {
padding: 8px 16px;
border: none;
border-radius: 4px;
background: rgba(255, 255, 255, 0.6);
cursor: pointer;
font-size: 16px;
}
.page-btns button:hover {
background: rgba(255, 255, 255, 0.9);
}
JavaScript (轮播图.js)
window.onload = function() {
var imgbox = document.querySelector(".imgbox");
imgbox.style.left = "0";
// 通用切换函数(支持边界循环)
var change = function(grp) {
var newPosition = parseInt(imgbox.style.left) + grp;
if (newPosition < -1600) newPosition = 0;
else if (newPosition > 0) newPosition = -1600;
imgbox.style.left = newPosition + "px";
};
// 自动轮播
setInterval(function() {
change(-800);
}, 4000);
// 上一张
document.querySelector(".left").onclick = function() {
change(800);
};
// 下一张
document.querySelector(".right").onclick = function() {
change(-800);
};
// 任意页跳转(直接赋值法)
document.querySelector(".first").onclick = function() {
imgbox.style.left = "0px";
};
document.querySelector(".second").onclick = function() {
imgbox.style.left = "-800px";
};
document.querySelector(".third").onclick = function() {
imgbox.style.left = "-1600px";
};
};