轮播图的代码
一个小小的建议
- 先要看得懂 -> 表示你听懂了 -> 如果看不懂, 那么直接问老师
- 自己写注释 -> 留着上课的代码, 自己写注释 -> 表示你理解了
- 看着自己的注释写代码 -> 某些方法不会, 自己去翻翻笔记 -> 表示你学会了
- 如果你能自己先写一个思路, 按照思路写代码 -> 表示你记住了
思路 - 获取元素
=> div.banner 需要的, 我们需要他的宽度
-> 因为 ul 一次运动就应该运动一个可视窗口的宽度
-> 因为每一张图片都和可视窗口一边宽
-> 一次运动一张图片, 就是运动一个可视窗口的宽度
=> ul.imgBox 需要的, 因为每次运动都是让这个 ul 在运动
-> 因为这个 ul 里面承载着若干个 li
-> ul 运动, 就会带着里面的所有 li 一起运动
=> ol.pointBox 需要的, 因为需要控制每一个 li 的类名
-> 每次运动结束以后, 我们需要控制 li 的类名切换
-> 每一个焦点按钮也需要一个点击事件
=> p.prev 需要的, 因为要有上一张的点击事件
=> p.next 需要的, 因为要有下一张的点击事件 - ol.pointBox 里面的 li 是动态创建还是直接写好
=> 如果直接写好, 那么我每加减一个图片, 也要对应的去操作
=> 也可以根据 ul.imgBox 盒子里面图片的数量来生成
=> 如果是生成的, 那么我每次加减图片的时候, 就不需要操心这个焦点了
=> 我们要根据 ul.imgBox 里面子元素的数量来创建对应的 li 添加到 ol.pointBox 里面 - 复制元素
=> 要把 ul.imgBox 里面本身的第一张复制一个
=> 要把 ul.imgBox 里面本身的最后一张复制一个
=> 复制的第一张放在最后, 复制的最后一张放在最前面 - 自动轮播
=> 每间隔一段时间, 让 ul.imgBox 向负方向移动一个可视窗口的距离
=> 每间隔一段时间, setInterval()
=> 让某一个元素移动一段距离, move() 函数
=> 我要知道你移动到第几张
=> 最开始准备一个变量记录是第几张 - 运动结束的时候拉回来
=> 需要在 move 函数的第三个参数, 也就是运动结束的时候做点事情
=> 当他走到最后一张的时候, 把他瞬间定位回到索引 [1] 的那一张
=> 运动结束的时候, 让焦点也改变一下
=> 和图片配套的焦点按钮有 active 类名, 让其余的所有焦点都没有类名 - 移入移出
=> 移入 banner 盒子的时候, 停止自动轮播, 清除定时器
=> 移出 banner 盒子的时候, 重新开启定时器, 继续自动轮播
=> 因为移入你有可能点击各种按钮(左右, 焦点) - 左右切换
=> 点击 p.next 就是看到下一张
=> 点击 p.prev 就是看到上一张
=> 下一张就是 index++
=> 上一张就是 index–
=> 都是依靠 move 函数来运动到上一张或者下一张 - 焦点切换
=> 每一个焦点按钮都有一个点击事件
=> 点击每一个焦点按钮的时候都能触发点事情
=> 你点击的是哪一个按钮, 就应该切换到对应的那一张图片上 - 解决鬼畜
=> 因为你每次点击(左右按钮, 焦点), 都会让轮播图切换
=> 当他没有切换完毕的时候, 你马上又进行了下一次点击
=> 他就会乱了, 因为他需要在运动结束以后, 判断 index 的值
=> 来决定是不是要拉回来, 你在他没有运动完毕, 就一直点击
=> index 一定会超过边界值
=> 解决问题:
-> 我们设置一个开关
-> 当他正在运动的时候, 我们把开关关闭
-> 我们的所有点击事件里面都进行判断
-> 只要开关是开着的, 那么我就执行点击的行为
-> 如果开关时关着的, 那么我就不执行点击的行为 - 切换标签页
=> 因为当你切换标签页, 或者最小化的时候
=> 我们叫做离开当前页面
=> 浏览器一旦离开当前页面, 那么 DOM 操作是会停止的
-> 但是定时器不会停
=> 就造成了一个问题, 定时器继续走着, 积攒了很多的 DOM 操作没有执行
=> 等到你切换回来的时候, 一次性把所有积攒的 DOM 操作全部执行了
=> 就会出现鬼畜现象
=> 解决问题:
-> 只要我能捕获到我离开当前页面的行为
-> 那么我就可以在离开页面的时候关闭定时器
-> 回到页面的时候再次执行自动轮播
=> 有一个事件叫做 visibilitychange 事件
-> 只能绑定在 document 上
-> 当前页面显示或者隐藏的时候就会触发
-> 离开页面会触发, 回到页面也会触发
=> 在 document 身上有一个属性叫做 visibilityState
-> 他的值决定了页面时显示还是隐藏
-> hidden 表示离开当前页面
-> visible 表示回到当前页面
// 1-1. 获取元素
// 最外层盒子
let bannerBox = document.querySelector(’.banner’)
// ul.imgBox 承载图片的盒子
let imgBox = document.querySelector(’.imgBox’)
// ol.pointBox 承载焦点按钮的盒子
let pointBox = document.querySelector(’.pointBox’)
// p.prev 上一张按钮
let prevBtn = document.querySelector(’.prev’)
// p.next 下一张按钮
let nextBtn = document.querySelector(’.next’)
// 1-2. 准备一些变量
// 准备一个 bannerBox 的宽度
let bannerWidth = bannerBox.clientWidth
// 准备一个记录索引的变量, 默认是 1
let index = 1
// 准备一个记录定时器返回值的变量
let timerId = 0
// 准备一个变量当作开关
let flag = true
// 2. 设置焦点
setPoint()
// 3. 复制元素
copyEle()
// 4. 自动轮播
autoPlay()
// 6. 移入移出
overOut()
// 7. 左右切换
leftRight()
// 8. 焦点切换
pointChange()
// 10. 切换页面
pageChange()
// 设置焦点的函数
function setPoint() {
// 2-1. 获取 imgBox 里面又多少个子元素
let pointNum = imgBox.children.length
// 2-2. 准备一个文档碎片, 用来承载焦点
let frg = document.createDocumentFragment()
// 2-3. 循环
for (let i = 0; i < pointNum; i++) {
// 2-4. 创建 li
let li = document.createElement(‘li’)
// 2-5. 第一个 li 默认有一个 active 类名
if (i === 0) li.className = ‘active’
// 2-6. 把创建好的 li 放在文档碎片里面
frg.appendChild(li)
}
// 2-7. 把文档碎片直接添加到 pointBox 里面
pointBox.appendChild(frg)
// 2-8. 重新设置一下 pointBox 的宽度, 避免焦点多了以后太拥挤
pointBox.style.width = pointNum * 20 * 1.5 + ‘px’
}
// 赋值元素的函数
function copyEle() {
// 3-1. 复制一个本身的第一张
let first = imgBox.firstElementChild.cloneNode(true)
// 3-2. 复制一个本身的最后一张
let last = imgBox.lastElementChild.cloneNode(true)
// 3-3. 把本身的第一张放在最后
imgBox.appendChild(first)
// 3-4. 把本身的最后一张放在最前面
imgBox.insertBefore(last, imgBox.firstElementChild)
// 3-5. 重新设置 imgBox 的宽度
imgBox.style.width = imgBox.children.length * 100 + ‘%’
// 3-6. 定位元素, 定位到第一张的位置
imgBox.style.left = -bannerWidth + ‘px’
}
// 自动轮播的函数
function autoPlay() {
// 4-1. 开启一个定时器, 每间隔一段时间换到下一张
timerId = setInterval(() => {
// 4-2. 准备的索引变量++
index++
// 4-3. 通过调用 move 函数让 imgBox 移动
move(imgBox, { left: -index * bannerWidth }, moveEnd)
}, 1000)
}
// 运动结束的函数
function moveEnd() {
// 这个函数会在一张图片运动结束后触发
// 这一张图片没有运动结束的时候, 不会触发这个函数
// 5-1. 判断运动到最后一张了, 我们把他瞬间定位到第一张
if (index === imgBox.children.length - 1) {
index = 1
imgBox.style.left = -index * bannerWidth + ‘px’
}
// 5-2. 判断当运动到索引为 0 的那一张, 瞬间定位到到数第二章
if (index === 0) {
index = imgBox.children.length - 2
imgBox.style.left = -index * bannerWidth + ‘px’
}
// 5-3. 让其余的所有焦点都没有类名
for (let i = 0; i < pointBox.children.length; i++) {
pointBox.children[i].className = ‘’
}
// 5-4. 让 index 对应的那一个焦点又类名
pointBox.children[index - 1].className = ‘active’
// 5-1 和 5-2 时判断要不要定位 imgBox
// 5-3 和 5-4 是在切换焦点按钮的类名
// 以上四个步骤都完毕以后, 表示一张图片运动结束了
// 该判断的也判断了, 该切换的也切换了
// 可以正常去切换下一张了
// 此时打开开关
// 9-2. 再次打开开关
flag = true
}
// 移入移出的函数
function overOut() {
// 6-1. 移入 banner 盒子的时候, 停止定时器
bannerBox.addEventListener(‘mouseover’, () => clearInterval(timerId))
// 6-2. 移出 banner 盒子的时候, 继续轮播
bannerBox.addEventListener(‘mouseout’, () => autoPlay())
}
// 左右切换的函数
function leftRight() {
// 7-1. 给上一张和下一张按钮绑定点击事件
prevBtn.addEventListener(‘click’, () => {
// 9-1. 判断开关来决定是不是执行切换上一张的行为
if (flag === false) return
flag = false
// 7-2. 操作上一张
index–
// 7-3. 通过调用运动函数让 imgBox 运动到上一张
move(imgBox, { left: -index * bannerWidth }, moveEnd)
})
nextBtn.addEventListener(‘click’, () => {
// 9-1. 判断, 如果开关是关着的, 那么我直接 return
if (flag === false) return
flag = false
// 7-2. 操作下一张
index++
// 7-3. 通过调用运动函数让 imgBox 运动到下一张
move(imgBox, { left: -index * bannerWidth }, moveEnd)
})
}
// 焦点切换的函数
function pointChange() {
// 8-1. 循环遍历每一个焦点按钮
for (let i = 0; i < pointBox.children.length; i++) {
// 8-2. 给每一个焦点按钮绑定点击事件
pointBox.children[i].addEventListener(‘click’, () => {
// 9-1. 通过判断开关来决定要不要执行切换到指定某一张的操作
if (flag === false) return
flag = false
// 8-3. 让 index 设置为焦点对应的那个数字
index = i + 1
// 8-4. 通过调用运动函数, 让 imgBox 运动到指定位置
move(imgBox, { left: -index * bannerWidth }, moveEnd)
})
}
}
// 切换页面的函数
function pageChange() {
// 10-1. 给 document 绑定一个 visibilitychange 事件
document.addEventListener(‘visibilitychange’, () => {
// 10-2. 通过判断 visibilityState 属性, 来决定时什么状态
// 一定要写 else if , 因为 visibilityState 属性一共有四种值
if (document.visibilityState === ‘hidden’) {
// 表示离开当前页面了
// 关闭定时器
clearInterval(timerId)
} else if (document.visibilityState === ‘visible’) {
// 表示回到当前页面了
// 开启自动轮播
autoPlay()
}
})
}
轮播图的代码
思路
- 获取元素
=> div.banner 需要的, 我们需要他的宽度
-> 因为 ul 一次运动就应该运动一个可视窗口的宽度
-> 因为每一张图片都和可视窗口一边宽
-> 一次运动一张图片, 就是运动一个可视窗口的宽度
=> ul.imgBox 需要的, 因为每次运动都是让这个 ul 在运动
-> 因为这个 ul 里面承载着若干个 li
-> ul 运动, 就会带着里面的所有 li 一起运动
=> ol.pointBox 需要的, 因为需要控制每一个 li 的类名
-> 每次运动结束以后, 我们需要控制 li 的类名切换
-> 每一个焦点按钮也需要一个点击事件
=> p.prev 需要的, 因为要有上一张的点击事件
=> p.next 需要的, 因为要有下一张的点击事件 - ol.pointBox 里面的 li 是动态创建还是直接写好
=> 如果直接写好, 那么我每加减一个图片, 也要对应的去操作
=> 也可以根据 ul.imgBox 盒子里面图片的数量来生成
=> 如果是生成的, 那么我每次加减图片的时候, 就不需要操心这个焦点了
=> 我们要根据 ul.imgBox 里面子元素的数量来创建对应的 li 添加到 ol.pointBox 里面
// 1. 获取元素
// 最外层盒子
let bannerBox = document.querySelector(’.banner’)
// 承载图片的 ul 盒子
let imgBox = document.querySelector(’.imgBox’)
// 承载焦点的 ol 盒子
let pointBox = document.querySelector(’.pointBox’)
// 上一张按钮
let prevBtn = document.querySelector(’.prev’)
// 下一张按钮
let nextBtn = document.querySelector(’.next’)
// 2. 根据图片数量创建焦点
setPoint()
轮播图的代码
思路 - 获取元素
=> div.banner 需要的, 我们需要他的宽度
-> 因为 ul 一次运动就应该运动一个可视窗口的宽度
-> 因为每一张图片都和可视窗口一边宽
-> 一次运动一张图片, 就是运动一个可视窗口的宽度
=> ul.imgBox 需要的, 因为每次运动都是让这个 ul 在运动
-> 因为这个 ul 里面承载着若干个 li
-> ul 运动, 就会带着里面的所有 li 一起运动
=> ol.pointBox 需要的, 因为需要控制每一个 li 的类名
-> 每次运动结束以后, 我们需要控制 li 的类名切换
-> 每一个焦点按钮也需要一个点击事件
=> p.prev 需要的, 因为要有上一张的点击事件
=> p.next 需要的, 因为要有下一张的点击事件 - ol.pointBox 里面的 li 是动态创建还是直接写好
=> 如果直接写好, 那么我每加减一个图片, 也要对应的去操作
=> 也可以根据 ul.imgBox 盒子里面图片的数量来生成
=> 如果是生成的, 那么我每次加减图片的时候, 就不需要操心这个焦点了
=> 我们要根据 ul.imgBox 里面子元素的数量来创建对应的 li 添加到 ol.pointBox 里面 - 复制元素
=> 要把 ul.imgBox 里面本身的第一张复制一个
=> 要把 ul.imgBox 里面本身的最后一张复制一个
=> 复制的第一张放在最后, 复制的最后一张放在最前面
// 1-1. 获取元素
// 最外层盒子
let bannerBox = document.querySelector(’.banner’)
// 承载图片的 ul 盒子
let imgBox = document.querySelector(’.imgBox’)
// 承载焦点的 ol 盒子
let pointBox = document.querySelector(’.pointBox’)
// 上一张按钮
let prevBtn = document.querySelector(’.prev’)
// 下一张按钮
let nextBtn = document.querySelector(’.next’)
// 1-2. 准备一些变量
// 获取到最外层盒子的宽度
let bannerWidth = bannerBox.clientWidth
// 2. 根据图片数量创建焦点
setPoint()
// 3. 复制 imgBox 里面的第一个和最后一个元素
copyEle()
// 创建焦点的方法
function setPoint() {
// 2-1. 获取到 ul.imgBox 这个元素下有多少个子元素
let pointNum = imgBox.children.length
// 2-2. 准备一个文档碎片(筐, DAY11 讲的)
let frg = document.createDocumentFragment()
// 2-3. 循环创建焦点 li
for (let i = 0; i < pointNum; i++) {
// 2-4. 随着循环创建 li
let li = document.createElement(‘li’)
// 2-5. 如果是第一个 li 要有一个 active 类名
if (i === 0) li.className = ‘active’
// 2-6. 把创建好的 li 放到筐里
frg.appendChild(li)
}
// 2-7. 都准备好了以后, 把筐里的内容添加到 ol.pointBox 里面
pointBox.appendChild(frg)
// 2-8. 重新根据焦点的个数设置一下 ol.pointBox 盒子的宽度
pointBox.style.width = pointNum * 20 * 1.5 + ‘px’
}
// 复制元素的方法
function copyEle() {
// 把 ul.imgBox 里面的第一张和最后一张复制一份
// 3-1. 复制第一个 li
// 复制的时候传递一个 tru