JS BOM 和 DOM 学习第五天(下)
目录
1.动画函数
1.1 缓动函数
- 运动速度不是匀速,速度是慢慢变化的
一个示例
- 说明
- 实现缓动动画,并可以在多个值之间移动
<!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">
<title>Document</title>
<style>
div{
position: absolute;
left: 0;
top: 100px;
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<button class="btn500">移动500px</button>
<button class="btn800">移动800px</button>
<div></div>
<script>
var div=document.querySelector('div');
// 封装缓动动画函数
function animateLow(obj,target){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
// 缓动原理,移动的距离越来越小
// 移动距离=(目标距离-当前移动距离)/10
var move=(target-obj.offsetLeft)/10;
// 移动距离取整,往大的方向取
// 移动距离为负数,往小的方向取
move=move>=0 ? Math.ceil(move) : Math.floor(move);
obj.style.left=obj.offsetLeft+move+'px';
// 停止
if(obj.offsetLeft==target){
clearInterval(obj.timer);
}
},50);
}
var btn500=document.querySelector('.btn500');
var btn800=document.querySelector('.btn800');
btn500.addEventListener('click',function(){
animateLow(div,500);
});
btn800.addEventListener('click',function(){
animateLow(div,800);
})
</script>
</body>
</html>
- 效果图
注意点
- 缓动移动的距离一般为浮点数,需要取整(注意如果距离为正-向上取整,距离为负-向下取整)
1.2 动画函数添加回调函数
- 原理:函数可以作为一个参数,将这个函数传递到另一个函数里面(作为形参),等另一个函数执行完毕后,在执行作为形参的函数,这个过程称为回调
<!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">
<title>Document</title>
<style>
div{
position: absolute;
left: 0;
top: 100px;
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<button class="btn500">移动500px</button>
<button class="btn800">移动800px</button>
<div></div>
<script>
var div=document.querySelector('div');
// 封装缓动动画函数
// 2.回调函数
// callback作为函数的形参(代表函数)
function animateLow(obj,target,callback){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
// 缓动原理,移动的距离越来越小
// 移动距离=(目标距离-当前移动距离)/10
var move=(target-obj.offsetLeft)/10;
// 移动距离取整,往大的方向取
// 移动距离为负数,往小的方向取
move=move>=0 ? Math.ceil(move) : Math.floor(move);
obj.style.left=obj.offsetLeft+move+'px';
// 停止
if(obj.offsetLeft==target){
clearInterval(obj.timer);
// 定时器的任务执行完毕后
// 执行回调函数
callback();
}
},50);
}
var btn500=document.querySelector('.btn500');
var btn800=document.querySelector('.btn800');
btn500.addEventListener('click',function(){
animateLow(div,500);
});
// 回调函数作为参数传递
btn800.addEventListener('click',function(){
animateLow(div,800,function(){
alert('你好');
});
})
</script>
</body>
</html>
- 效果图
1.3 动画函数封装后的调用
- 封装的动画js
function animateLow(obj,target,callback){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
// 缓动原理,移动的距离越来越小
// 移动距离=(目标距离-当前移动距离)/10
var move=(target-obj.offsetLeft)/10;
// 移动距离取整,往大的方向取
// 移动距离为负数,往小的方向取
move=move>=0 ? Math.ceil(move) : Math.floor(move);
obj.style.left=obj.offsetLeft+move+'px';
// 停止
if(obj.offsetLeft==target){
clearInterval(obj.timer);
// 定时器的任务执行完毕后
// 执行回调函数
if(callback){
callback();
}
}
},15);
}
- 调用动画
<!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">
<title>Document</title>
<style>
.sliderbar{
width: 50px;
height: 50px;
position: absolute;
right: 0;
top: 300px;
overflow: hidden;
}
.sliderbar span{
width: 50px;
height: 50px;
background-color: skyblue;
position: absolute;
left: 0;
top: 0;
z-index: 10;
text-align: center;
line-height: 50px;
}
.sliderbar div{
box-sizing: border-box;
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 50px;
background-color: pink;
padding-left: 30px;
line-height: 50px;
}
</style>
<script src="./01.动画函数.js"></script>
</head>
<body>
<div class="sliderbar">
<span> ← </span>
<div class="box">我是内容</div>
</div>
<script>
var span=document.querySelector('span');
var div=document.querySelector('.box');
var sliderbar=document.querySelector('.sliderbar');
span.addEventListener('mouseenter',function(){
sliderbar.style.overflow='visible';
animateLow(div,-150,function(){
span.innerHTML='→';
})
})
span.addEventListener('mouseout',function(){
animateLow(div,0,function(){
span.innerHTML='←';
sliderbar.style.overflow='hidden';
})
})
</script>
</body>
</html>
- 效果图
2. 轮播图
- 思路
无缝轮播的原理
- 额外添加一张banner图(第一张图),放在最后,当移动到倒数第二张时,再点击右滑按钮,执行:
- 倒数第二张到最后一张的动画过渡
- 1执行完毕后,设置大图(所有轮播图)的left,使大图的第一张替换(第一张移动到轮播盒子中心)最后一张(过程不需要过渡),肉眼不可见,实现无缝
- 左滑的原理
- 第一张再点击左移按钮
- 先用最后一张(与第一张相同)替换(最后一张移动到轮播盒子中心)第一张(过程不需要过渡)
- 实现最后一张到倒数第二张的过渡
一个轮播图案例
<!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">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
/* 轮播图盒子 */
.box{
width: 800px;
height: 505px;
background-color: pink;
margin: 100px auto;
position: relative;
overflow: hidden;
}
/* 左箭头按钮 */
.left{
width: 22px;
height: 32px;
position: absolute;
left: 0;
top: 50%;
z-index: 1000
}
/* 右箭头按钮 */
.right{
width: 22px;
height: 32px;
position: absolute;
right: 0;
top: 50%;
z-index: 1000;
}
/* 左右箭头宽高由a盒子决定 */
.right img,
.left img{
width: 100%;
height: 100%;
}
/* ul要设置足够宽的宽度,在一行能放下4个小li */
ul{
position: absolute;
left: 0;
top: 0;
overflow: hidden;
list-style: none;
width: 600%;
}
/* 每个li宽度为ul的1/6 */
ul li{
width: 800px;
/* display: block; */
float: left;
height: 100%;
}
/* 可点击范围扩大 */
ul li a{
display: block;
width: 100%;
height: 100%;
}
/* 图片与li宽度一致 */
ul li a img{
display: block;
width: 100%;
height: 100%;
}
/* ol轮播指示器水平居中 */
ol{
position: absolute;
list-style: none;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(255,255,255,.5);
border-radius: 12px;
z-index: 100;
}
ol li{
float: left;
}
ol li a{
display: block;
margin: 6px;
width: 12px;
height: 12px;
border-radius: 50%;
/* ps */
border: 1px solid #fff;
}
/* 选中状态 */
ol li a.current{
display: block;
margin: 6px;
width: 12px;
height: 12px;
border-radius: 50%;
/* ps */
background-color: #fff;
}
.clearfix::after,
.clearfix::before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix{
*zoom: 1;
}
</style>
</head>
<body>
<div class="box clearfix">
<a class="left" href="javascript:;">
<img src="./images/arrow-prev.png" alt="">
</a>
<a class="right" href="javascript:;">
<img src="./images/arrow-next.png" alt="">
</a>
<ul class="banner">
<li>
<a href="javascript:;">
<img src="./images/focus.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="./images/focus1.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="./images/focus2.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="./images/focus3.jpg" alt="">
</a>
</li>
</ul>
<!-- 底部轮播按钮部分 -->
<ol class="circle">
</ol>
</div>
<script src="./16.动画封装成js文件/01.动画函数.js"></script>
<script>
var left=document.querySelector('.left');
var right=document.querySelector('.right');
var box=document.querySelector('.box');
var timer=null;
// 鼠标移入banner图显示左右箭头
box.addEventListener('mouseenter',function(){
left.style.display='block';
right.style.display='block';
clearInterval(timer);
timer=null;
})
// 鼠标移出banner图隐藏左右箭头
box.addEventListener('mouseleave',function(){
left.style.display='none';
right.style.display='none';
timer=setInterval(function(){
right.click();
},2000);
})
var ul=document.querySelector('.banner');
var ol=document.querySelector('.circle');
// console.log(ul.children.length);
// 循环生成轮播指示器的个数
for(var i=0;i<ul.children.length;i++){
var li=document.createElement('li');
var a=document.createElement('a');
a.href='#';
// 生成banner图的个数
// 给ol的li中的a设置下标
a.setAttribute('index',i);
li.appendChild(a);
ol.appendChild(li);
}
// 设置第一个小圆圈为选中状态
ol.children[0].children[0].className='current';
// 克隆第一个li标签,放在最后,用于实现无缝轮播
var li1=ul.children[0].cloneNode(true);
ul.appendChild(li1);
// 这也是个思路,额外两图
// 克隆最后一个标签到最前面
// var li2=ul.children[ul.children.length-2].cloneNode(true);
// console.log(li2);
// ul.insertBefore(li2,ul.children[0]);
// 显示第二张图片
// ul.style.left=-ul.clientWidth/6+'px';
// 记录当前图片序号,从0开始
var numr=0;
// 点击轮播指示器,指示器小圆圈变实体白色
ol.addEventListener('click',function(e){
var target=e.target;
// 排他思想
for(var i=0;i<ol.children.length;i++){
ol.children[i].children[0].className='';
}
target.className='current';
// 实现图片的移动,也就是ul的移动
var index=target.getAttribute('index');
var step=index*ul.clientWidth/6;
step=Math.ceil(step);
// console.log(-step);
animateLow(ul,-step);
// 同步numr值
numr=parseInt(index);
})
// 左右箭头移动
// 右侧按钮实现右滑
right.addEventListener('click',function(){
// 移动到最后一张时检测,迅速换成第一张
if(numr===ul.children.length-1){
ul.style.left='0px';
numr=0;
}
// 如果时最后一张,实现第一张与第二张的过渡
numr++;
var step=numr*(ul.clientWidth/6);
animateLow(ul,-step);
console.log(numr);
check(numr);
})
// 左侧按钮实现左滑
left.addEventListener('click',function(){
// 如果已经是第一张再次左滑
// 先移到最后一张
if(numr===0){
numr=ul.children.length-1;
ul.style.left=-(ul.clientWidth/6)*(numr)+'px';
}
// 再实现最后一张与倒数第二张的切换
numr--;
var step=numr*ul.clientWidth/6;
animateLow(ul,-step);
check(numr);
})
// 循环检测轮播图按钮显示
function check(numr){
// 排他思想
for(var i=0;i<ol.children.length;i++){
ol.children[i].children[0].className='';
}
var circle;
// 特殊情况,5个图片,1个重复
circle=numr;
if(numr===-1){
circle=ul.children.length-2;
}else if(numr===4){
circle=0;
}
// console.log(index);
ol.children[circle].children[0].className='current';
// console.log(ol.children);
}
// 刷新界面进入一次
timer=setInterval(function(){
right.click();
},2000);
</script>
</body>
</html>
- 效果图
3. 节流阀
-
目的:防止轮播图按钮连续点击造成播放过快
-
节流阀目的:当一个函数动画内容执行完毕,再去执行下一个动画函数,让事件无法连续触发
-
核心开发思路:利用回调函数,添加一个变量控制,锁住函数和解锁函数
-
具体步骤
- 设置一个变量:var flag=true;
- if(flag){flag=false;dosomething} 关闭水龙头
- 利用回调函数 :动画执行完毕,打开水龙头
示例
- 防止右滑按钮点击过快
var flag=true;
right.addEventListener('click',function(){
if(flag){
// 关闭水龙头
flag=false;
// 移动到最后一张时检测,迅速换成第一张
if(numr===ul.children.length-1){
ul.style.left='0px';
numr=0;
}
// 如果时最后一张,实现第一张与第二张的过渡
numr++;
var step=numr*(ul.clientWidth/6);
// 回调函数打开水龙头
animateLow(ul,-step,function(){
flag=true;
});
console.log(numr);
check(numr);
}
})
- 效果图
##4. 返回顶部案例
- 滚动窗口至文档的特定位置
window.scroll(x,y)
-
x,y不跟单位,直接写数字(x,y代表距离顶部的距离)
-
x,y为0时,回到顶部
思路
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.slider-bar {
position: absolute;
left: 50%;
top: 300px;
margin-left: 600px;
width: 45px;
height: 130px;
background-color: pink;
}
.w {
width: 1200px;
margin: 10px auto;
}
.header {
height: 150px;
background-color: purple;
}
.banner {
height: 250px;
background-color: skyblue;
}
.main {
height: 1000px;
background-color: yellowgreen;
}
span {
display: none;
position: absolute;
bottom: 0;
}
</style>
</head>
<body>
<div class="slider-bar">
<span class="goBack">返回顶部</span>
</div>
<div class="header w">头部区域</div>
<div class="banner w">banner区域</div>
<div class="main w">主体部分</div>
<script>
// 获取banner
var banner=document.querySelector('.banner');
var sliderbar=document.querySelector('.slider-bar');
var bannerTop=banner.offsetTop;
// 固定定位后的距离
var sliderTop=sliderbar.offsetTop-bannerTop;
// 获取main
var main=document.querySelector('.main');
var mainTop=main.offsetTop;
// 获取回到顶部
var goBack=document.querySelector('.goBack');
// 当页面被卷去的距离为banner区域的offsetTop时,滚动导航栏变为固定单位
document.addEventListener('scroll',function(){
if(window.pageYOffset>=bannerTop){
sliderbar.style.position='fixed';
sliderbar.style.top=sliderTop+'px';
}else{
sliderbar.style.position='absolute';
sliderbar.style.top='300px';
}
if(window.pageYOffset>=mainTop){
goBack.style.display='block';
}else{
goBack.style.display='none';
}
goBack.addEventListener('click',function(){
// window.scroll使窗口滚动到顶部
// window.scroll(0,0);
// 2.使用缓动函数实现带动画的回到顶部
animateLow(window,0);
})
function animateLow(obj,target,callback){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
// 缓动原理,移动的距离越来越小
// 移动距离=(目标距离-当前移动距离)/10
var move=(target-obj.pageYOffset)/10;
// 移动距离取整,往大的方向取
// 移动距离为负数,往小的方向取
move=move>=0 ? Math.ceil(move) : Math.floor(move);
// obj.style.left=obj.offsetLeft+move+'px';
obj.scroll(0,move+obj.pageYOffset);
// 停止
if(obj.pageYOffset==target){
clearInterval(obj.timer);
// 定时器的任务执行完毕后
// 执行回调函数
if(callback){
callback();
}
}
},15);
}
})
</script>
</body>
</html>
- 效果图
5.筋斗云首页案例
- 思路分析
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0
}
ul {
list-style: none;
}
body {
background-color: black;
}
.c-nav {
width: 900px;
height: 42px;
background: #fff url(images/rss.png) no-repeat right center;
margin: 100px auto;
border-radius: 5px;
position: relative;
}
.c-nav ul {
position: absolute;
}
.c-nav li {
float: left;
width: 83px;
text-align: center;
line-height: 42px;
}
.c-nav li a {
color: #333;
text-decoration: none;
display: inline-block;
height: 42px;
}
.c-nav li a:hover {
color: white;
}
.cloud {
position: absolute;
left: 0;
top: 0;
width: 83px;
height: 42px;
background: url(images/cloud.gif) no-repeat;
}
</style>
<script src="./01.动画函数.js"></script>
<script>
window.addEventListener('load',function(){
var cloud=document.querySelector('.cloud');
var nav=document.querySelector('.c-nav');
// console.log(nav);
// 获取所有的小li
// 使用冒泡
// nav.addEventListener('mouseover',function(e){
// var target=e.target;
// console.log(target);
// console.log(target.offsetLeft);
// cloud.style.left=target.offsetLeft+'px';
// })
// 冒泡a和li不好区分
var list=nav.querySelectorAll('li');
var space=0;
for(var i=0;i<list.length;i++){
// 经过时移动
list[i].addEventListener('mouseover',function(){
animateLow(cloud,this.offsetLeft);
});
// 离开时返回原值
list[i].addEventListener('mouseout',function(){
animateLow(cloud,space);
})
// 点击时修改space的默认值
list[i].addEventListener('click',function(){
space=this.offsetLeft;
})
}
})
</script>
</head>
<body>
<div id="c_nav" class="c-nav">
<span class="cloud"></span>
<ul>
<li><a href="#">首页新闻</a></li>
<li><a href="#">师资力量</a></li>
<li><a href="#">活动策划</a></li>
<li><a href="#">企业文化</a></li>
<li><a href="#">招聘信息</a></li>
<li><a href="#">公司简介</a></li>
<li><a href="#">我是佩奇</a></li>
<li><a href="#">啥是佩奇</a></li>
</ul>
</div>
</body>
</html>
- 效果图