步骤
轮播图1 HTML+CSS
轮播图2 动态生成页面
通过 JavaScript程序 生成 div标签中 所有 轮播图需要的标签
生成 ul ol div 标签节点
根据数组动态生成 原始 ul>li ol>li
ul > li > img
ol > li
第一个li添加 class,active
将生成的 ul>li ol>li 字符串 写入 ul ol 标签节点
将 ul ol div 标签节点 写入 轮播图div中
获取 原始 ul>li ol>li 标签对象
克隆 第一个ul>li 和 最后一个 ul>li
将 克隆的第一个ul>li 写入 ul末位
将 克隆的最后一个ul>li 写入 ul起始
重新设定ul宽度
是 当前li个数 * li宽度
默认显示 原始轮播图的第一张 也就是 克隆写入之后的 第二个li
ul 默认 向左 定位 一个li宽度
轮播图3 自动轮播
通过 move() 运动函数 以动画效果完成ul标签定位的切换
自动轮播函数
定义一个全局变量 用于 存储 显示li标签的索引下标
初始值 是 1
通过 修改 变量中 的的数值 表示 显示的 li标签
也就是 通过 修改变量中存储的数值 控制 轮播图的执行
定义定时器
变量定义数值累加1
设定 焦点按钮的样式
设定 ul定位的数值
负的 当前显示的li标签 索引下标 * li宽度
通过 move() 运动函数 来 执行 ul标签定位的改变
move( ul标签 , { left : 负的index数值乘以li宽度 } , 运动结束触发的回调函数 )
焦点按钮设定函数
清除 所有的 ol>li 样式
给 显示的ul>li 对应的 ol>li 添加样式
如果 显示 当前ul>li的最后一个 给 第一个ol>li 添加样式
如果 是其他情况
给 显示的ul>li 索引下标 -1 对应的 ol>li 添加样式
ul切换运动终止的回调函数
如果 显示当前ul>li的最后一个
运动结束 给 index 赋值 1
也就是 要显示 当前ul>li的第二个
通过css样式设定 瞬间完成 ul定位的切换
ul标签对象.style.left = -index * li宽度 + 'px'
轮播图4 鼠标移入移出
给 轮播图div标签 添加事件
鼠标移入
终止轮播图的自动运行
也就是 清除 自动轮播 定时器
鼠标移出
再次执行轮播图的自动轮播
也就是 再次调用 autoLoop() 自动轮播函数
轮播图5 点击事件
给 一直存在的轮播图div添加点击事件
通过事件委托的语法形式 给标签添加点击事件
左右切换按钮
左切换按钮
显示上一次张
也就是 显示li标签索引下标 累减 1
根据 新的显示li标签的索引下标 定位ul标签
通过 move运动函数 运动完成 ul标签的定位切换
右切换按钮
显示下一次张
也就是 显示li标签索引下标 累加 1
根据 新的显示li标签的索引下标 定位ul标签
通过 move运动函数 运动完成 ul标签的定位切换
焦点按钮
显示 点击的 ol>li 对应的 ul>li 标签
也就是 ol>li 标签的索引下标 + 1
是 对应的 ul>li 标签的索引下标
根据 新的显示li标签的索引下标 定位ul标签
通过 move运动函数 运动完成 ul标签的定位切换
轮播图6 防止点击过快
定义变量 存储默认值
触发点击事件 执行程序之前 先判断 变量储存的数据
如果是 原始值
变量赋值 其他数值 正常 执行之后的程序
如果是 其他数值
执行 return 终止 执行之后的程序
当 move() 运动函数执行结束 也就是 ul标签定位切换结束
给 变量 赋值 原始值true
可以执行下一次move()运动函数了
轮播图7 轮播图最小化隐藏
当 浏览器 最小化 / 隐藏 / 显示其他程序时
浏览器 会在 window操作系统 的 后台运行
浏览器 本身 不会触发执行任何程序
但是 浏览器中 JavaScript程序 会继续执行
也就是 autoLoop() 中的定时器 会自动继续执行
也就是 ul标签的定位 会被改变
解决方案:
浏览器最小化隐藏时
清除 定时器
浏览器显示时
再次 启动自动轮播函数
visibilitychange事件
添加个 document 的事件
浏览器显示状态监听事件
当浏览器显示状态改变时触发设定的函数程序
document.visibilityState
浏览器显示状态描述
hidden
隐藏最小化状态
清除定时器
visible
显示状态
再次调用 自动轮播函数
代码(面向对象编程)
HTML部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./iconfont.ttf">
<link rel="stylesheet" href="./iconfont.css">
<title>Document</title>
<style>
*{
padding: 0;
margin: 0;
}
li{
list-style: none;
}
a{
text-decoration: none;
}
.banner{
margin: auto;
width: 1920px;
height: 1030px;
border: 2px solid red;
position: relative;
background-color: black;
overflow: hidden;
}
.banner ul{
width: 600%;
height: 1030px;
position: absolute;
left: 0;
top: 0;
}
.banner ul li{
width: 1920px;
height: 1030px;
float: left;
}
.banner ol{
width: 400px;
height: 80px;
position: absolute;
bottom: 50px;
left: 50%;
transform: translateX(-50%);
background-color: rgb(0, 0, 0,0.4);
border-radius: 30px;
display: flex;
justify-content: space-around;
align-items: center;
cursor: pointer;
}
.banner ol li{
width: 30px;
height: 30px;
margin: 20px;
border-radius: 50%;
background-color: white;
}
.banner div {
padding: 0 30px;
box-sizing: border-box;
width: 100%;
height: 80px;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-100%);
display: flex;
justify-content: space-between;
align-items: center;
}
.banner div a{
font-size: 60px;
color: white;
}
.banner ol .active{
width: 45px;
height: 45px;
transition: 1s;
background-color: red;
}
.banner div span{
background-color: rgb(14, 13, 13,0.6);
border-radius: 30%;
box-sizing: border-box;
display: block;
padding: 20px 20px;
transition: all 0.5s;
}
.banner div span:hover{
background-color: red;
font-size: 70px;
}
</style>
</head>
<body>
<div class="banner"></div>
<script src="./move.js"></script>
<script src="./ind.js"></script>
<script>
//定义数组模拟后端传参
const arr = [{url:'./image/1.png'},
{url:'./image/2.png'},
{url:'./image/6.png'},
{url:'./image/4.png'},
{url:'./image/5.png'}];
const oBanner = document.querySelector(".banner");
const obj = new CreateTabObj( oBanner , arr );
// 入口函数调用
obj.init();
</script>
</body>
</html>
JavaScript部分
class CreateTabObj {
constructor(elment, msgArr) {
// 获取标签对象
this.ele = elment;
// 数组模拟数据库
this.arr = msgArr;
//创建ul ol div节点
this.oUl;
this.oOl;
this.oDiv;
this.liWidth;
this.ulLis;
this.olLis;
this.time;
this.index = 1;
this.res = true;
}
// 入口函数
// 在一个函数中调用所有需要执行的函数程序
// 也就是 只要 调用一个函数 就调用了所有需要调用的函数
// 入口函数 必须定义名称是 init
init() {
this.theTag();
this.slideshow();
this.theMouseMoves();
this.theMouseClick();
this.hide();
}
// 动态生成标签内容函数
theTag() {
//创建ul ol div节点
this.oUl = document.createElement('ul');
this.oOl = document.createElement('ol');
this.oDiv = document.createElement('div');
// 设定节点内容
this.oDiv.innerHTML = '<a href="JavaScript:;"><span name="left" class="iconfont icon-zuofanye"></span></a><a href="JavaScript:;"><span name="right" class="iconfont icon-youfanye"></span></a>'
//循环遍历数组动态写入内容
let oUlstr = '';
let oOlstr = '';
this.arr.forEach(function (item, key) {
// item 是 数组单元的数据数值 也就是 存储图片数据的对象
// 动态生成 ul>li
oUlstr += `<li><img src="${item.url}"></li>`;
// 动态生生 ol>li
// 给 第一个li标签 添加class,active 也就是 背景颜色是红色
// 给 每个li标签 添加 num属性属性值是索引下标
oOlstr += key === 0 ? `<li name = "ollis" class = "active" num = ${key}></li>` : `<li name = "ollis" num = ${key}></li>`
})
// 将 生成的字符串 写入 标签节点中
this.oUl.innerHTML = oUlstr;
this.oOl.innerHTML = oOlstr;
// 添加节点,添加到div中
this.ele.appendChild(this.oUl);
this.ele.appendChild(this.oOl);
this.ele.appendChild(this.oDiv);
//获取生成的 原始 ul>li ol>li标签对象
this.ulLis = this.oUl.querySelectorAll('li');
this.olLis = this.oOl.querySelectorAll('li');
//获取标签宽度
this.liWidth = this.ulLis[0].offsetWidth;
// 克隆标签
let ulLisFirst = this.ulLis[0].cloneNode(true);
let ulLisLast = this.ulLis[this.ulLis.length - 1].cloneNode(true);
// 将 克隆的第一个 写入 ul的最后
this.oUl.appendChild(ulLisFirst)
// 将 克隆的最后一个 写入 ul的起始
this.oUl.insertBefore(ulLisLast, this.ulLis[0]);
// 重新设定ul宽度
// 克隆之后li标签个数 * li标签宽度
// 克隆之后li标签个数是数组单元个数+2
this.oUl.style.width = (this.arr.length + 2) * this.liWidth + 'px';
// 将ul向左定位一个li的宽度
this.oUl.style.left = -this.liWidth + 'px';
}
//自动轮播函数
slideshow() {
// 设定定时器
this.time = setInterval(() => {
if (this.res) {
this.res = false;
} else {
return;
}
// 变量累加1
this.index++;
// index变量累加后 设定 对应的焦点样式
this.point();
// 通过 move() 运动函数 完成 ul标签 定位的切换
// 回调函数使用 bind() 方法 修改this指向
// 当前 this 指向实例化对象 修改回调函数的this指向是当前this也就是实例化对象
move(this.oUl, { left: -this.index * this.liWidth }, this.circulation.bind(this))
}, 2000)
}
//move运动函数执行结束触发的回调函数
circulation() {
// 如果是 当前ul的最后一个li 运动结束 立即切换到 当前ul的第二个li
// 也就是 index 是 最后一个li的索引下标 也就是 arr.length+2-1
// 切换到 当前ul的第二个li 也就是 index 赋值 1
if (this.index === this.arr.length + 2 - 1) {
this.index = 1;
// 如果是 当前ul的第一个li 运动结束 立即切换到 当前ul的倒数二个li
// 也就是 index 是 第一个li的索引下标 也就是 0
// 切换到 当前ul的倒数第二个li 也就是 index 赋值 arr.length+2-1-1
} else if (this.index === 0) {
// 给 变量 赋值 当前ul的倒数第二个li的索引下标
this.index = this.arr.length + 2 - 2
}
// 给 ul 执行定位 瞬间切换
// 根据新的index数值 给 ul标签 做瞬间定位切换
this.oUl.style.left = -this.index * this.liWidth + 'px';
// 运动结束 也就是 一次ul切换完成
// 给变量赋值原始值 可以 执行下一次运动
this.res = true;
}
//焦点图函数
point() {
// 清除所有的ol>li焦点样式
this.olLis.forEach((item) => {
item.classList.remove('active');
})
// 如果 显示 当前ul中最后一个li 给 ol>li 中的 第一个添加样式
if (this.index === this.arr.length + 2 - 1) {
// 给 索引是0 的 第一个 ol>li 添加 css样式
this.olLis[0].classList.add('active');
// 如果 显示 点券ul中第一个li 给 ol>li 中的 最后一个添加样式
} else if (this.index === 0) {
// 给 ol>li 的最后一个 添加 css样式
this.olLis[this.olLis.length - 1].classList.add('active');
// 其他情况 给 当期ul>li索引下标 -1 对应的 ol>li 添加样式
} else {
// 当前 显示的ul>li的索引下标 也就是 index
// 数值 -1 是 对应的 ol>li 的 索引下标
this.olLis[this.index - 1].classList.add("active");
}
}
//鼠标移入移出函数
theMouseMoves() {
// 鼠标移入
this.ele.addEventListener('mouseenter', () => {
// 清除定时器
clearInterval(this.time);
})
// 鼠标移出
this.ele.addEventListener('mouseleave', () => {
// 再次调用自动轮播
this.slideshow();
})
}
//点击事件函数
theMouseClick() {
// 给 轮播图div添加点击事件
this.ele.addEventListener('click', (e) => {
// 判断 如果 事件对象 e.target 的name属性值是 left 点击的是左切换按钮
if (e.target.getAttribute('name') === "left") {
// 防止点击过快
if (this.res) {
this.res = false;
} else {
return;
}
// 切换显示上一个li
// 也就是 索引下标 累减 1
this.index--;
// 调用函数 重新设定 焦点按钮css样式
this.point();
// 根据新的索引下标 通过move()运动函数
// 动画效果 完成ul标签的重新定位
move(this.oUl, { left: -this.index * this.liWidth }, this.circulation.bind(this));
} else if (e.target.getAttribute('name') === "right") {
// 判断 如果 事件对象 e.target 的name属性值是 right 点击的是左切换按钮
if (this.res) {
this.res = false;
} else {
return;
}
this.index++;
this.point();
move(this.oUl, { left: -this.index * this.liWidth }, this.circulation.bind(this));
} else if (e.target.getAttribute('name') === "ollis") {
// 判断 如果 事件对象 e.target 的name属性值是 olLi 点击的是焦点按钮
if (this.res) {
this.res = false;
} else {
return;
}
// 获取当前 点击的ol>li标签 num属性的属性值
// 也就是 点击的ol>li标签的 索引下标
// num属性值+1 是 对应的 ul>li 的索引下标
// num属性值 是 字符串类型 必须要转化为数值类型 再 执行+1 运算
this.index = Number(e.target.getAttribute('num')) + 1;
this.point();
move(this.oUl, { left: -this.index * this.liWidth }, this.circulation.bind(this));
}
})
}
// 浏览器最小化隐藏
hide() {
// 给 document 添加 浏览器显示状态监听
document.addEventListener('visibilitychange', () => {
// 如果 浏览器显示状态描述 是 hidden
if (document.visibilityState === 'hidden') {
// 证明当前浏览器隐藏最小化
// 清除定时器
clearInterval(this.time);
// 如果 浏览器显示状态描述 是 visible
} else if (document.visibilityState === 'visible') {
// 证明当前浏览器 显示
// 再次调用 自动轮播函数
this.autoLoop();
}
})
}
}
运行结果
总结
控制轮播图的核心
就是 控制 变量中的存储的数值
也就是 控制 显示 li标签的索引下标
通过 设定 ul标签的定位 是 变量 * li宽度
也就是 设定 ul标签的定位 显示 变量对应索引下标对应的li标签