1.图片自动轮播,对应的页码数高亮
(文件大小有限,以致于速度太快了😣😣)
2.点击页码可以跳转到对应的图片
3.鼠标进入盒子,显示左右箭头,暂停轮播;鼠标移出盒子,图片轮播继续
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
list-style: none;
border: 0;
}
.all {
width: 500px;
height: 200px;
padding: 7px;
border: 1px solid #ccc;
margin: 100px auto;
position: relative;
}
.screen {
width: 500px;
height: 200px;
overflow: hidden;
position: relative;
}
.screen li {
width: 500px;
height: 200px;
overflow: hidden;
float: left;
}
.screen ul {
position: absolute;
left: 0;
top: 0px;
width: 3500px;
}
.all ol {
position: absolute;
right: 10px;
bottom: 10px;
line-height: 20px;
text-align: center;
}
.all ol li {
float: left;
width: 20px;
height: 20px;
background: #fff;
border: 1px solid #ccc;
margin-left: 10px;
cursor: pointer;
}
.all ol li.current {
background: yellow;
}
#arr {
display: none;
}
#arr span {
width: 40px;
height: 40px;
position: absolute;
left: 5px;
top: 50%;
margin-top: -20px;
background: #000;
cursor: pointer;
line-height: 40px;
text-align: center;
font-weight: bold;
font-family: '黑体';
font-size: 30px;
color: #fff;
opacity: 0.3;
border: 1px solid #fff;
}
#arr #right {
right: 5px;
left: auto;
}
</style>
<script src="js/get.js"></script>
<script src="js/animation.js"></script>
</head>
<body>
<div class="all" id='box'>
<div class="screen">
<ul>
<li><img src="images/laugh01.gif" width="500" height="200" /></li>
<li><img src="images/laugh02.gif" width="500" height="200" /></li>
<li><img src="images/laugh03.gif" width="500" height="200" /></li>
<li><img src="images/laugh04.gif" width="500" height="200" /></li>
<li><img src="images/laugh05.gif" width="500" height="200" /></li>
</ul>
<ol>
<li class="current">1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
</div>
<div id="arr"><span id="left"><</span><span id="right">></span></div>
</div>
<script>
// 需求1:鼠标移入到显示图片的位置,就显示对应的箭头,鼠标移出就隐藏箭头
/*
思路分析
1.获取事件源:div#box盒子
2.事件类型:鼠标的移入onmouseover和移出onmouseout
3.确定事件处理
3.1 移入:显示div#arr display = block
3.2 移出:隐藏div#arr display = none
*/
// 1.获取事件源:div#box盒子
let box = getId('box');
let arr = getId('arr');
// 自动轮播:向右 延时器处理
// 定时器
let timeId = setInterval(rightClick, 2000);
// 2.事件类型:鼠标的移入onmouseover和移出onmouseout
// 3.确定事件处理
// 3.1 移入:显示div#arr display = block
box.onmouseover = function () {
arr.style.display = 'block';
// 清除自动轮播(定时器)
clearInterval(timeId);
};
// 3.2 移出:隐藏div#arr display = none
box.onmouseout = function () {
arr.style.display = 'none';
// 加载自动轮播(定时器)
timeId = setInterval(rightClick, 2000);
};
/*
需求2:实现左右按钮的无缝轮播
思路分析:
1.特别思路,实现轮播图的无缝连接,会在原来的图片上Ul>li,第一张的前面增加一张最后的图片,还会在最后一张的后面增加第一张图片
1.1 获取屏幕部分:get('.screen')
1.2 获取屏幕下面的图片部分: 屏幕.querySelectorAll('ul>li')
1.3 克隆两个:第一个li和最后一个li(深克隆)
1.4 将克隆出来的第一个元素放到ul的最后,将克隆出来的最后一个元素放到ul的第一个li之前
1.5 让图片正常显示:显示第一张,让ul瞬间移动到第一张
2.获取事件源:两个 getId('left') getId('right')
3.确定事件类型:点击事件 onclick
4.事件处理
* 定义一个观察者:index = 1 前面动态添加了一张最后的图片:占了0的位置
4.1 right的点击事件 right.onlick = rightClick;
4.1.1 index++:但是要注意 index 不能超过5
4.1.2 根据index的值 * screen.offsetWidth 做动画效果
4.2 left的点击事件 left.onclick = leftClick;
4.2.1 index--:但是要注意 index 不能小于1
4.2.2 根据index的值 * screen.offsetWidth 做动画效果
*/
// 1.特别思路,实现轮播图的无缝连接,会在原来的图片上Ul>li,第一张的前面增加一张最后的图片,还会在最后一张的后面增加第一张图片
let screen = get('.screen');
// 获取所有的li
let lis = screen.querySelectorAll('ul>li');
let ols = screen.querySelectorAll('ol>li');
// console.log(lis);
// 克隆两个元素:第一个li和最后一个li
let firstLi = lis[0].cloneNode(true); // 深克隆
let lastLi = lis[lis.length - 1].cloneNode(true); // 深克隆
// console.log(firstLi, lastLi);
// 最后一张放第一个位置,第一张放最后一个位置
lis[0].parentNode.insertBefore(lastLi, lis[0]); // 在第一张之前插入最后一张
lis[0].parentNode.appendChild(firstLi);
// 1.5 让图片正常显示:显示第一张,让ul瞬间移动到第一张
screen.firstElementChild.style.left = '-500px';
// 2.获取事件源:两个 getId('left') getId('right')
let left = getId('left');
let right = getId('right');
// 3.确定事件类型:点击事件 onclick
// 4.事件处理
// * 定义一个观察者:index = 1 前面动态添加了一张最后的图片:占了0的位置
let index = 1;
// 4.1 right的点击事件 right.onlick = rightClick;
right.onclick = rightClick;
function rightClick() {
// 4.1.1 index++:但是要注意 index 不能超过5
if (index == 5) {
// 说明:已经是最后一张,要看第一张
index = 1;
// 瞬移到第一张
lis[0].parentElement.style.left = '0px';
} else {
index++;
}
// 4.1.2 根据index的值 * screen.offsetWidth 做动画效果
animateMove(lis[0].parentElement, -index * screen.offsetWidth);
// 4.1.3 让对应的页面高亮显示:当前页面正常显示,上一个页面应该不显示
ols[index - 1].classList.add('current');
// 如果当前是第一张图片:index = 1,是从最后一张过来的
ols[index > 1 ? index - 2 : ols.length - 1].classList.remove('current');
}
// 4.2 left的点击事件 left.onclick = leftClick;
left.onclick = leftClick;
function leftClick() {
// 4.2.1 index--:但是要注意 index 不能小于1
// 如果index当前已经是1,第一张,用户在点击left,想看第5张
// 1.将当前的效果瞬移到最后一张(就是第一张):障眼法,瞬移用户看不到效果
if (index == 1) {
lis[0].parentNode.style.left = '-3000px';
// index重置为5
index = 5;
} else {
index--;
}
// 4.2.2 根据index的值 * screen.offsetWidth 做动画效果
animateMove(lis[0].parentElement, -index * screen.offsetWidth);
// 4.2.3 根据index实现页面的高亮显示
ols[index == 5 ? 0 : index].classList.remove('current');
ols[index - 1].classList.add('current');
}
// 页码点击事件
ols.forEach(function (item, key) {
// item就是ol>li
item.addEventListener('click', function () {
// 页码变化效果:原始页码(删掉current)
ols[index - 1].classList.remove('current');
// 动画:当前index是key + 1
index = key + 1;
// 动画
animateSlow(lis[0].parentElement, { left: -index * screen.offsetWidth });
// 页码变化效果:当前图片对应的页码显示
this.classList.add('current');
});
});
// 总结
// 轮播图:原生代码实现
// 轮播图的实现如果要考虑无缝轮播,一般的思路是添加首尾两张图片
// 第一张的前面放最后一张,最后一张的后面放第一张:用来瞬移,做障眼法,欺骗用户
</script>
</body>
</html>
get.js
/* 当前文件封装获取元素的API */
/**
* 通过ID获取元素
* @param {string} id
* @return {element} 获取到的元素 或者 null
* */
function getId(id) {
return document.getElementById(id);
}
/**
* 根据选择器获取一个元素
* @param {string} selector
* @return {element} 获取到的元素 或者 null
*
*/
function get(selector) {
return document.querySelector(selector);
}
/**
* 根据选择器获取多个元素
* @param {string} selector
* @return {element} 获取到的伪数组
*
*/
function getAll(selector) {
return document.querySelectorAll(selector);
}
animation.js
/**
* 动画效果封装
* @param {element} obj,要移动的元素
* @param {number} target,目标位置,不带单位
* @param {number} step = 10,每次移动的效果,默认为10px
* @param {number} time = 20,每次间隔多久实现定时器的触发,默认20ms
*
* */
function animateMove(obj, target, step = 10, time = 20) {
// 先清理定时器:防止用户多次触发
// 基于对象.非标准属性,不会出现在元素中,只能在内存中存在:我们可以选择将元素自己的定时器存储到自己的属性当中
// console.log(obj.timeId);
clearInterval(obj.timeId);
// 定时器处理
obj.timeId = setInterval(function () {
// 获取到元素的left的值:offset
let currentLeft = obj.offsetLeft;
// 求出下一个次的位置:有可能target已经比当前元素的位置currentLeft小
// 判定目标与当前元素的位置的关系
// console.log(currentLeft, target);
// let声明的变量是块级作用域:如果是在if里面声明,if外面不能用:在外面声明,在里面赋值
let next;
// 添加一个开关:控制向左还是向右
let toRight = true; // 默认向右
if (currentLeft < target) {
// 元素在左,目标在右
next = currentLeft + step;
} else {
// 元素在右,目标在左
next = currentLeft - step;
// 改变开关
toRight = false;
}
// console.log(next);
// 判定next是否超出了目标
if (toRight) {
// 动画是向右:判定当前的next应该小于等于target才移动
if (next < target) {
// 还没过线
obj.style.left = next + 'px';
} else {
// 过线了
obj.style.left = target + 'px';
// 已经到了
clearInterval(obj.timeId);
}
} else {
// 动画是向左:判定当前的next应该大于等于target才移动
if (next >= target) {
// 没有过线
obj.style.left = next + 'px';
} else {
// 过线了
obj.style.left = target + 'px';
// 到达终点
clearInterval(obj.timeId);
}
}
}, time);
}
function animateSlow(obj, target, step = 0.1, time = 20, fn = '') {
// 防止用户多次操作
clearInterval(obj.timeId);
// 开始定时器
obj.timeId = setInterval(function () {
// 增加一个开关
let isAllOk = true; // 认定所有的属性,都已经到位了
// 获取当前用户需要的样式属性,然后进行相应的数据改变
// 传入的target是一个对象,样式的属性名字 是对象的属性名,要拿到只能遍历
for (let key in target) {
// key 就是属性名 ,target[key]就是值
// console.log(key, target[key]);
// 以前获取方式:固定做左右,利用offsetLeft拿到位置,现在属性为left
// 以前是不能使用obj[key],因为obj.style.语法只能获取行内
// console.log(obj.style[key]); // 等价于 obj.style.left,以前
// 现在有办法拿到行外样式:getComputedStyle(元素对象)[key]
// console.log(getComputedStyle(obj)[key]);
let current = getComputedStyle(obj, null)[key]; // 带单位:不能参与数学运算
current = parseInt(current);
// console.log(current);
// 计算步长:移动的距离
let steps = (target[key] - current) * step;
// console.log(steps);
// 上述steps有可能是负值:向左移动
steps = steps > 0 ? Math.ceil(steps) : Math.floor(steps);
// 一步完成
// steps = target[key] > current ? Math.ceil((target[key] - current) * step) : Math.floor((target[key] - current) * step);
// console.log(steps);
// 下一个位置
let next = current + steps;
// 修改元素的样式:修改元素样式,只有一个方式 obj.style[key]
obj.style[key] = next + 'px';
// 判定
// if (next == target[key]) {
// // 到头了
// clearInterval(obj.timeId);
// }
// 判定:判定开关
if (next != target[key]) {
// 没有到位:关闭开关
isAllOk = false;
}
// console.log(key, target[key], next, isAllOk);
}
// 开关确定定时器是否结束
if (isAllOk) {
// 清空定时器
clearInterval(obj.timeId);
// 如果用户传入了回调函数,帮助用户调用:typeof可以判定出是否是函数
if (typeof fn == 'function') {
// 说明用户传入了一个函数:帮助用户调用
fn();
}
}
// 终止计时器
// clearInterval(obj.timeId);
}, time);
}