js动画原理
1.匀速
2.碰撞
.box{height: 100px;width: 100px;background: #333;position: absolute;left: 0;right: 0;} .box1{left: 500px;top: 500px;}
<input type="text" id="te"> <div class="box"></div><div class="box1"></div>
设定一些基础变量
var oText = document.getElementById("te"); var oDiv = document.querySelector(".box"); var oDiv2 = document.querySelector(".box1"); var speedX = 30;//设置一个速度变量, var speedY = 30; oDiv.speedX = 15;//设置div横向速度 oDiv.speedY = 3;//设置div纵向速度 oDiv2.speedX = 18; oDiv2.speedY = 2;
给一个元素加个速度移动元素的方法
function move(el){ var currentLeft = parseInt(window.getComputedStyle(el).left);//取得元素当前距离父元素左边的距离 var currentTop = parseInt(window.getComputedStyle(el).top);//取得元素当前距离父元素上边的距离 check_border_conllision(el);//引用下边的构造函数判断元素是否到达了页面边缘 var left = currentLeft + el.speedX;//设置一个速度让div距离页面左边的位置 var top = currentTop + el.speedY; el.style.left = left + 'px';//将取得速度后的距离父元素的左边距离赋值给元素 el.style.top = top + 'px'; }
盒子碰撞到了页面边缘检测核心构造函数
function check_border_conllision(el){ var elStyle = window.getComputedStyle(el); var left = parseInt(elStyle.left); var top = parseInt(elStyle.top); var w = parseInt(elStyle.width);//div的宽度 var h = parseInt(elStyle.height); if(left < 0){//如果左侧位置是负值,则将它设为0,平移值转换 left = 0; el.speedX *= -1; } if(left > window.innerWidth - w){//如果现在的左侧距离大于了页面宽度减去div的宽度,表示右边已经撞上了。 left = window.innerWidth -w; el.speedX *= -1; } if(top < 0){//如果距离父元素上边的距离小于0,表示碰到了上边的边缘,将元素的速度取一个负值 top = 0; el.speedY *= -1; } if(top > window.innerHeight - h){//如果距离大于父元素底部的距离,将元素的速度取一个负值 top = window.innerHeight - h; el.speedY *= -1; } el.style.left = left + 'px';//重新设定元素距离父元素左边的距离 el.style.top = top + 'px'; }
检测两个盒子相撞核心构造函数
function check_conllision(el,el2){ var style1 = window.getComputedStyle(el); var style2 = window.getComputedStyle(el2); var left1 = parseInt(style1.left); var left2 = parseInt(style2.left); var top1 = parseInt(style1.top); var top2 = parseInt(style2.top); var w1 = parseInt(style1.width); var w2 = parseInt(style2.width); var h1 = parseInt(style1.height); var h2 = parseInt(style2.height); var style1Zx = {x:left1 + w1 / 2,y:top1 + h1 / 2};//箱子1的中心点位置 var style2Zx = {x:left2 + w2 / 2,y:top2 + h2 / 2};//箱子2的中心点位置 var leftc = Math.abs(style1Zx.x - style2Zx.x);//将两个箱子中心点横向距离相减取绝对值 var topc = Math.abs(style1Zx.y - style2Zx.y); if(leftc <= (w1 + w2)/2 && topc <= (h1 + h2)/2){//如果箱子的中心点小于他们的高度和宽度一半之和,我们判断为相撞 return true; } return false; }
加入了碰撞构造函数的移动元素的构造函数
function move2(el){ var currentLeft = parseInt(window.getComputedStyle(el).left); var currentTop = parseInt(window.getComputedStyle(el).top); check_border_conllision(el); var tempX, tempY; if(check_conllision(oDiv,oDiv2)){//判断是否相撞,将箱子的速度互换 tempX = oDiv.speedX; tempY = oDiv.speedY; oDiv.speedX = oDiv2.speedX; oDiv.speedY = oDiv2.speedY; oDiv2.speedX = tempX; oDiv2.speedY = tempY; } var left = currentLeft + el.speedX;//设置div距离页面左边的位置 var top = currentTop + el.speedY; el.style.left = left + 'px'; el.style.top = top + 'px'; } setInterval(() => {//设定一个调用函数,时间为20毫秒 move2(oDiv);move2(oDiv2); }, 20);
动画函数的封装
1.getStyle
2.减速
3.透明度
4.多属性
var oDiv = document.querySelector("div"); function getStyle(el,property){//ie8兼容性,构造函数取得元素的style return el.currentStyle ? el.currentStyle[property] :window.getComputedStyle(el)[property]; } function animateEl(el,properties,fn){ clearInterval(el.timer);//先将调用函数清除 el.timer = setInterval(function() {//设定周期调用函数 var stop = true;//设定一个值,是否运算得到的属性都匹配然后终止定时器。
for(var property in properties){//遍历对象中的键名 var curpro;//设定一个当前属性的值 var target = properties[property];//将对象中的目标值取出来 if(property == "opacity"){//如果属性是opacity curpro = Math.round(parseFloat(getStyle(el,property)) * 100);//将当前属性值乘以100取整,方便计算speed target = parseFloat(target)*100;//将目标也乘以100 }else{ curpro = parseFloat(getStyle(el,property));//width如果使用parseInt,所以用了parseFloat,不会得到指定值,其他属性可以 } var speed = (target - curpro) / 30;//目标距离减去当前距离除以30作为速度。 speed = speed > 0 ? Math.ceil(speed): Math.floor(speed);//设定速度,如果速度大于0,则向上取整,至少为1,相反为-1; if(properties[property] != curpro){//如果第一次运算的属性没有达到指定值,则返回stop为false
stop = false;
}
if(property == "opacity"){ el.style[property] =(curpro + speed)/100 ;//设定元素的属性值,因为之前已经成了100,所以除以100 }else{ el.style[property] =curpro + speed + "px";//如果不是透明属性,加上px, } }
if(stop){//如果第一次运算得到的值匹配了指定值,让定时器停止
clearInterval(el.timer);
fn && fn();//因为停止了第一个定时器,需要开启下一次运算,用回调函数来决定。这个意思是你返回一个函数,则调用这个函数。
}
}, 20); }
animateEl(oDiv,{"top":300,"width":300,"opacity":0.5});
自己练习写的
var speedCa = (opacity1 - targetFL)/30 ; speedCa = speedCa / 100; speedCa.toFixed(8);//如果指定值和现值很接近,则速度将会很小,所以先取小数点后面8个数, el.style[property] = opacity1/100 - speedCa; if(parseFloat(el.style[property]).toFixed(2) == parseFloat(target).toFixed(2)){//如果已经很接近,则直接将指定值赋值给现值 el.style[property] = target; clearInterval(timer1); }
轮播
1.透明度变化轮播
![](https://img2018.cnblogs.com/blog/465592/201910/465592-20191008194821132-1066947243.jpg)
.slideimg{height: 200px;width: 500px;position: relative;border: 5px solid #333;overflow: hidden;} .slideimg .ul1 .item{position: absolute;list-style: none;opacity: 0;} .slideimg .ul1 .item img{height: 200px;width: 500px;display: block;} .slideimg .ul1 .item:first-of-type{opacity: 1;} .slideimg .pre,.slideimg .next{height: 60px;width: 30px;opacity: .5;background: #333;position: absolute;top:50%;margin-top: -30px;cursor: pointer;} .slideimg .pre{left: 0;} .slideimg .next{right: 0;} .slideimg .ul2{position: absolute;bottom: 5px;left:50%;margin-left: -50px;width: 100px;} .slideimg .ul2 .li{height: 20px;width: 20px;border-radius: 20px;background: rgba(000, 000, 000, .5);list-style: none; cursor: pointer;float: left;margin-left: 5px} .slideimg .ul2 .li.focus{background:rgba(255, 000, 000, .5)}
<div class="slideimg"> <ul class="ul1"> <li class="item"><img src="../img/1.jpg" alt="1"></li> <li class="item"><img src="../img/2.jpg" alt="2"></li> <li class="item"><img src="../img/3.jpg" alt="3"></li> <li class="item"><img src="../img/4.jpg" alt="4"></li> </ul> <ul class="ul2"> <li class="li focus"></li><li class="li"></li><li class="li"></li><li class="li"></li> </ul> <div class="pre"></div><div class="next"></div> </div>
var preIndex,nextIndex,len,id;//当前页赋值给这个数,当前显示页面,图片总数, var ul2li = document.querySelectorAll(".ul2 li");//全局对象圆点跳转图片 init(); function init(){//初始化 preIndex = nextIndex = 0;//初始化参数,将前一页后一页的下标清零 len = document.querySelectorAll(".ul1 .item").length; document.querySelector(".next").onclick = function(){//点击右侧按钮显示下一张图片 slideNext(); } document.querySelector(".pre").onclick = function(){ slidePre(); } var slideImg = document.querySelector(".slideimg"); slideImg.onmouseover = function(){//鼠标悬停 stop(); } slideImg.onmouseout = function(){ sildeAuto(); } sildeAuto();//自动轮播
点击下面的圆点跳转图片
for(i = 0; i < ul2li.length ; i++){//遍历所有的圆点 ul2li[i].index = i;//将当前的下标赋值给index ul2li[i].onclick = function(){ preIndex = nextIndex; nextIndex = this.index; slideTo(preIndex,nextIndex); } } } function sildeAuto(){//3秒自动轮播 clearInterval(id); id = setInterval(function(){ slideNext(); },3000); } function slidePre(){//向前封装函数 preIndex = nextIndex; nextIndex--; if(nextIndex === - 1){ nextIndex = len - 1; } slideTo(preIndex,nextIndex); } function slideNext(){//向后封装函数 preIndex = nextIndex; nextIndex++; if(nextIndex === len){ nextIndex = 0; } slideTo(preIndex,nextIndex); } function stop(){//停止周期调用函数 clearInterval(id); } function slideTo(pre,next){//透明度函数封装 var item = document.querySelectorAll(".ul1 .item"); ul2li[pre].className = "li"; ul2li[next].className = "li focus"; animateEl(item[pre],{opacity:0});//调用上面的封装函数 animateEl(item[next],{opacity:1}); }
2.水平轮播
![](https://img2018.cnblogs.com/blog/465592/201910/465592-20191008194851145-729861409.jpg)
.slideimg2{height: 200px;width: 400px;position: relative;border: 5px solid #333;overflow: hidden;} .slideimg2 .list{position: absolute;list-style: none;} .slideimg2 .list .item{float: left;width: 400px;height: 200px;} .slideimg2 .list .item img{height: 200px;width: 400px;display: block;} .slideimg2 .preimg,.slideimg2 .nextimg{height: 60px;width: 30px;opacity: .5;background: #333;position: absolute;top:50%;margin-top: -30px;cursor: pointer;} .slideimg2 .preimg{left: 0;} .slideimg2 .nextimg{right: 0;} .slideimg2 .list2{position: absolute;bottom: 5px;left:50%;margin-left: -50px;width: 100px;display: flex;justify-content:space-around} .slideimg2 .list2 .dot{height: 20px;width: 20px;border-radius: 20px;background: rgba(000, 000, 000, .5);list-style: none; cursor: pointer;} .slideimg2 .list2 .dot.focus{background: rgba(255, 000, 000, .5)}
<div class="slideimg2"> <ul class="list"> <li class="item"><img src="../img/1.jpg" alt="1"></li> <li class="item"><img src="../img/2.jpg" alt="2"></li> <li class="item"><img src="../img/3.jpg" alt="3"></li> <li class="item"><img src="../img/4.jpg" alt="4"></li> </ul> <ul class="list2"> <li class="dot focus"></li><li class="dot"></li><li class="dot"></li><li class="dot"></li> </ul> <div class="preimg"></div><div class="nextimg"></div> </div>
var sIndex,len,liWidth,liItem,idin; var list = document.querySelector(".slideimg2 .list"); var dot = document.querySelectorAll(".slideimg2 .list2 .dot"); init() function init(){ sIndex = 1;//设定默认显示第一张图片 var newLi1 = document.querySelector(".slideimg2 .list .item:first-of-type"); var copy1 = newLi1.cloneNode(true);//复制第一张图片 var newLi4 = document.querySelector(".slideimg2 .list .item:last-of-type").cloneNode(true); var copyLast = newLi4.cloneNode(true);//复制最后一张图片 list.appendChild(copy1);//将第一张图片添加到最后一个 list.insertBefore(copyLast,newLi1);//将最后一张图片添加到第一个 liItem = document.querySelectorAll(".list .item"); var liStyle = window.getComputedStyle(liItem[0]); liWidth = liStyle.width;//取到一个li的宽度 list.style.left = -parseInt(liWidth) + "px";//让图片显示初始值第一个 len = liItem.length;//取到总li的个数 list.style.width = parseInt(liWidth) * len +"px";//list的宽度=li个数乘以li的宽度,让所有图片横排 //左按钮播放一下张图片 document.querySelector(".slideimg2 .preimg").onclick = function(){ preImg(); } //右按钮播放一下张图片 document.querySelector(".slideimg2 .nextimg").onclick = function(){ nextImg(); } //鼠标悬停 document.querySelector(".slideimg2").onmouseover = function(){ stop(); } //鼠标离开自动轮播 document.querySelector(".slideimg2").onmouseout = function(){ auto(); } auto();//自动轮播函数 //小圆点逻辑 for(var i = 0; i < dot.length ; i++){ dot[i].index = i;//将下标占时存入index dot[i].onclick = function(){ sIndex = this.index + 1;//因为按钮的下一页前后都多了一张图片,所以小圆点的下标要加1, sliTo(sIndex); } } } function auto(){//调用函数自动轮播 clearInterval(idin); idin = setInterval(function(){ nextImg(); },3000); } function stop(){ clearInterval(idin);//停止周期调用函数 } function preImg(){//前一张图片的构造函数 sIndex--; if(sIndex === -1){//如果上一张图片到了第一张,则直接跳转到后面相同的图片 sIndex = len -3;//因为设定了轮播图片是4张,加上前后两张一共6张。 list.style.left = -parseInt(liWidth) * 4 + "px";//立即移动图片, } sliTo(sIndex);//调用滚动核心构造函数 } function nextImg(){ sIndex++; if(sIndex === len){//如果下一张图片到了最后一张,则直接跳转到前面相同的图片, sIndex = 2; list.style.left = -parseInt(liWidth) + "px"; } sliTo(sIndex); } function sliTo(index){//滚动核心构造函数 var foucusDot;//平衡小圆点和左右按钮的逻辑 if(index === 0){ foucusDot = dot.length -1;//当按钮最左面一张图片对应小圆点的最后一张图片的下标 }else if(index === 5){//当按钮最右面一张图片对应小圆点的第一张图片的下标 foucusDot = 0; }else{ foucusDot = index - 1;//按钮的下标比小圆点的下标多1. } document.querySelector(".focus").className = "dot";//检索小圆点取消有focus的样式 dot[foucusDot].className = "dot focus";//添加小圆点当前页的突出显示 animateEl(list,{left:-parseInt(liWidth)*index}) ;//封装动画函数,整个list进行left的位移 }