小概
本章的学习内容:原生js写轮播图(匀速动画应用),缓动动画的封装和使用,导航栏筋斗云案例(缓动动画应用)
提示:以下是本篇文章正文内容,下面案例可供参考
1. 轮播图案例(淘宝滚动型)
- 轮播图的应用基本在每个电商网站上都可以看见,应用场景非常广泛。下面我们用原生js实现轮播图的制作
- 图片轮播的原理就是使用上一章我们封装的匀速动画实现的:在css样式中,把所有需要展示的图片连接成一张长图,为父盒子设置overflow: hidden(溢出裁剪), 通过匀速动画修改该图片的letf值达到展示不同图片的效果 下面是css样式
<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: 3000px;
}
.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>
</head>
<body>
<div class="all" id='box'>
<div class="screen">
<ul>
<li><img src="images/01.jpg" width="500" height="200" /></li>
<li><img src="images/02.jpg" width="500" height="200" /></li>
<li><img src="images/03.jpg" width="500" height="200" /></li>
<li><img src="images/04.jpg" width="500" height="200" /></li>
<li><img src="images/05.jpg" width="500" height="200" /></li>
<li><img src="images/01.jpg" 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>
1.2 需求分析
1.鼠标移入移出box:显示/隐藏arr箭头盒子
2.鼠标单击上一页/下一页:滚动到对应下标的图片
* 注意点:实现无限循环
3.鼠标单击页码:滚动到对应下标的图片
4.自动轮播:定时器实现
需要用到上期的匀速动画封装函数
/**
* @description:匀速动画
* @param {number}target : 目标位置
* @param {dom}ele : 目标元素
* @return:
*/
function animationMove(target, ele) {
//1.开始动画之前先清除之前的定时器,以本次移动为准
clearInterval(ele.timeID);
//2.开始本次动画
ele.timeID = setInterval(function () {
//2.1 获取元素当前位置
let currentLeft = ele.offsetLeft;
/* 使用布尔类型存储移动方向 true:从左往右 false:从右往左*/
let isLeft = target >= currentLeft ? true : false;
//2.2 开始移动
isLeft ? currentLeft += 10 : currentLeft -= 10;
ele.style.left = currentLeft + 'px';
//2.3 边界检测
/*
这个语法是一个比较表达式,比较两边式子结果是否一致
左边: isLeft 布尔类型 true:从左往右 false:从右往左
右边: currentLeft >= target 结果布尔类型
(1)当isLeft为true(从左往右),只有当右边式子也为true才会成立
(2)当isLeft为false(从右往左),只有当右边式子也为false才会成立。此时只有当currentLeft < target的时候右边式子才是false
*/
if (isLeft == currentLeft >= target) {
//停止动画
clearInterval(ele.timeID);
//元素复位
ele.style.left = target + 'px';
};
}, 20);
};
1.3 功能1 功能2
1.鼠标移入移出box:显示/隐藏arr箭头盒子
2.鼠标单击上一页/下一页:滚动到对应下标的图片
// 1. 获取页面元素
let box = document.querySelector('#box'); // 父盒子
let screen = document.querySelector('.screen'); // 轮播图展现父盒子
let ul = screen.children[0];//图片列表
let ol = screen.children[1];//页码列表
let arr = document.querySelector('#arr');//arrow箭头盒子
let left = arr.children[0];//上一页
let right = arr.children[1];//上一页
//声明一个全局变量:存储当前的图片下标
let index = 0;
//2.注册事件
//2.1 鼠标移入box
box.onmouseover = function () {
//3.事件处理:显示箭头arr盒子
arr.style.display = 'block';
};
//2.2 鼠标移出box
box.onmouseout = function () {
//3.事件处理:隐藏箭头arr盒子
arr.style.display = 'none';
};
//2.3 点击下一页
right.onclick = function () {
//3. 事件处理:滚动到对应下标的图片 index++
// 3.1 计算对应下标
if (index == ul.children.length - 1) {
index = 0;
} else {
index++;
}
console.log(index);
// 3.2 开始滚动
animationMove(-index * screen.offsetWidth, ul);
// 3.3 排他思想修改页码样式
for (let i = 0; i < ol.children.length; i++) {
if (i == index) {
ol.children[i].className = 'current';
} else {
ol.children[i].className = '';
}
}
};
//2.4 点击上一页
left.onclick = function () {
//3. 事件处理:滚动到对应下标的图片 index--
// 3.1 计算对应下标
if (index == 0) {
index = 4;
} else {
index--;
}
console.log(index);
// 3.2 开始滚动
animationMove(-index * screen.offsetWidth, ul);
// 3.3 排他思想修改页码样式
for (let i = 0; i < ol.children.length; i++) {
if (i == index) {
ol.children[i].className = 'current';
} else {
ol.children[i].className = '';
}
}
};
1.4 实现循环轮播
其实上已经实现了无限轮播,但是出现了一个问题,第5张下一张到第一张的时候,切换方式是直接左移到第一张,这种切换方式有问题。
解决方法:视觉欺骗
将第一张图片复制到最后一张图片的后面,实际上就有6张图片了,只不过第一张与最后一张是同一张,判断下标为5时,index=0 ;ul.style.left = -index*(照片宽度),相当于第六张切到第一张的时候 瞬间切换到第一张, 然后展示第一张切换第二张的动画。
还会出现一个问题,就是页码(0 1 2 3 4)与图片的下标不对应(0 1 2 3 4 5);
解决方法:判断当图片[[5]时,给页码[0]设置样式、
//2.3 点击下一页
right.onclick = function () {
//3. 事件处理:滚动到对应下标的图片 index++
// 3.1 计算对应下标
if (index == ul.children.length - 1) {
index = 0;
ul.style.left = -index*screen.offsetWidth + 'px'; // 重点:轮播图无限轮播的秘密,视觉欺骗
}
index++;
console.log(index);
// 3.2 开始滚动
animationMove(-index * screen.offsetWidth, ul);
// 3.3 排他思想修改页码样式
for (let i = 0; i < ol.children.length; i++) {
if (i == index ) {
ol.children[i].className = 'current';
} else {
ol.children[i].className = '';
}
}
if(index == ul.children.length-1){
ol.firstElementChild.className = 'current';
}
};
//2.4 点击上一页
left.onclick = function () {
//3. 事件处理:滚动到对应下标的图片 index--
// 3.1 计算对应下标
if (index == 0) {
index = ul.children.length-1;
ul.style.left = -index*screen.offsetWidth +'px';
}
index--;
console.log(index);
// 3.2 开始滚动
animationMove(-index * screen.offsetWidth, ul);
// 3.3 排他思想修改页码样式
for (let i = 0; i < ol.children.length; i++) {
if (i == index) {
ol.children[i].className = 'current';
} else {
ol.children[i].className = '';
}
}
};
1.5 功能3 功能4
实现鼠标单击页码,跳到对应的图片上
实现自动轮播,鼠标移入停止轮播,离开继续轮播
//2.5 页码点击
for (let i = 0; i < ol.children.length; i++) {
ol.children[i].onclick = function () { //i =0 1 2 3 4
//事件处理 this:当前点击的页码
console.log(i);
// 3.1 开始滚动
animationMove(-i*screen.offsetWidth,ul);
// 3.2 设置index与当前点击的页码一致
index =i;
// 3.3 排他思想修改样式
for(let j=0;j<ol.children.length;j++){
if(i==j){
ol.children[j].className = 'current';
}else{
ol.children[j].className = '';
}
}
}
}
// 开启自动轮播
let timeID = setInterval(function(){
right.onclick();
},2000);
//2.1 鼠标移入box
box.onmouseover = function () {
//3.事件处理:显示箭头arr盒子
arr.style.display = 'block';
//清除自动轮播
clearInterval(timeID);
};
//2.2 鼠标移出box
box.onmouseout = function () {
//3.事件处理:隐藏箭头arr盒子
arr.style.display = 'none';
//开启自动轮播
timeID = setInterval(function(){
right.onclick();
},2000);
};
2. 缓速动画
- 什么是缓动动画 : 速度由快到慢的动画
匀速: 速度不变
变速: 速度变化,更符合现实世界物体运动规律
2. 缓动动画核心原理 : 本次移动距离 = (目标位置-当前位置)/10
3. 缓动动画特点
3.1 需要取整 : 因为缓动动画公式是除法,而除法会产生小数。 像素一般不给小数的,所以需要取整。
3.2 没有误差 : 因为缓动动画公式计算到最后每次只移动1px
* 不需要边界检测: current >= target , 元素复位
* 需要终点检测 : current == target
缓速动画与匀速动画的区别,
缓速动画;每次移动的值 =(目标距离-当前距离)/10 ,不需要边界检测,移动方向不用判断(向右移动移动距离向上取整, 向左移动移动距离向下取整)
匀速动画:每次移动固定的值,需要边界检测,需要判断移动方向,需要复位、
function animationSlow(target,ele){
//1.先清除以前的定时器,以本次移动为准
clearInterval(ele.timeID);
//2.开始本次动画
ele.timeID = setInterval(function(){
//2.1.获取当前位置
let currentLeft = ele.offsetLeft;
//2.2.计算本次移动距离 = (目标位置-当前位置)/10
let step = (target-currentLeft)/10;
//取整 ; 正数:从左往右,向上取整 负数:从右往左,向下取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//2.3.开始移动
currentLeft += step;
ele.style.left = currentLeft + 'px';
//2.4.终点检测
if( currentLeft == target){
clearInterval(ele.timeID);
};
},20);
};
3. 筋斗云案例
- 缓速动画的金典案例
<style>
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
body {
background-color: #333;
}
.nav {
width: 800px;
height: 42px;
margin: 100px auto;
/*background-color: red;*/
background: #fff url(images/rss.png) no-repeat right center;
border-radius: 10px;
position: relative;
}
.nav li {
width: 83px;
height: 42px;
/*background-color: red;*/
text-align: center;
line-height: 42px;
float: left;
cursor: pointer;
}
ul {
position: relative;
}
.nav span {
position: absolute;
top: 0;
left: 0;
width: 83px;
height: 42px;
background: url(images/cloud.gif) no-repeat;
}
</style>
</head>
<body>
<div class="nav">
<span id="cloud"></span>
<ul id="navBar">
<li>首页</li>
<li>博客</li>
<li>程序员学院</li>
<li>下载</li>
<li>论坛</li>
<li>问答</li>
<li>代码</li>
<li>直播</li>
</ul>
</div>
</body>
</html>
<script src="./animation.js"></script> //封装了匀速和缓速的两个函数方法
<script>
/*需求分析
1.鼠标移入每一个li元素: 筋斗云缓动到移入的li元素位置
2.鼠标移出每一个li元素: 筋斗云缓动到 主人的位置
3.鼠标单击每一个li元素: 筋斗云 主人变成单击的li元素
*/
//1.获取元素
let cloud = document.querySelector('#cloud');
let liList = document.querySelectorAll('#navBar>li');
//声明一个全局变量存储筋斗云的主人(默认第一个li元素)
let zhuren = liList[0];
//2.注册事件
for(let i = 0;i<liList.length;i++){
//2.1 移入
liList[i].onmouseover = function(){
//3.事件处理 this: 移入的li元素
animationSlow(this.offsetLeft,cloud);
};
//2.2 移出
liList[i].onmouseout = function(){
//3.事件处理 this: 移出的li元素
animationSlow(zhuren.offsetLeft,cloud);
};
//2.3 单击
liList[i].onclick = function(){
//3.事件处理 this: 单击的li元素
zhuren = this;
};
};
</script>
总结
匀速动画和缓速动画两个知识点很重要,尤其是利用匀速动画制作轮播图和筋斗云这两个案例,非常的金典 肥常的好用。虽然现在组件很多,写项目的时候直接调用就可以,但是这并不影响我准备敲他‘10’遍的。好记性不如敲烂指头,奥力给!