动画
- 定义:运动的图片(让图片或者图画动起来)。
- 原理:未来位置等于当前位置加上步长(盒子的位置 = 盒子本身所在位置 + 步长)。
- 位置获取和赋值方式:用
style.left赋值
,用offsetLeft获取值
;style.left获取值不方便,只能获取行内式,如果没有就返回"",容易出现NaN,即使有值也是包含px的字符串;offsetLeft获取值特别方便,而且获取到的值是现成的number类型,方便计算,因为它是只读的不能赋值,所以一般用style.left赋值。
动画的种类
闪现(很少使用)
<body>
<button>闪动</button>
<div></div>
<script src="../05-jQuery/jquery-1.11.1.js"></script>
<script type="text/javascript">
var btn = $("button");
var divs = $("div");
$(btn[0]).click(function () {
divs[0].style.left = "500px";
});
</script>
</body>
匀速(重点
)
<body>
<button>匀动到200</button>
<button>匀动到400</button>
<div></div>
<script>
var btn200 = document.getElementsByTagName("button")[0];
var btn400 = document.getElementsByTagName("button")[1];
var div = document.getElementsByTagName("div")[0];
var timer = null;
btn200.onclick = function () {
animation(200);
};
btn400.onclick = function () {
animation(400);
};
function animation(distance) {
timer = setInterval(function () {
div.style.left = div.offsetLeft + 10 + "px";
if (div.offsetLeftd == distance){
clearInterval(timer);
}
},30);
}
</script>
</body>
- 系列bug:
- 定时器:多次使用定时器之后,动画会越来越快:
- 解决方案:
在使用定时器之前,先清除定时器
。
- 解决方案:
- 不能返回:
- 解决方案:判断目标位置和当前位置的大小,如果目标位置大,步进就为正,否则就为负。
- 如果目标位置和当前位置的距离小于步进,就不再进行运动,但是会出现抖动现象:
- 解决方案:直接令当前位置等于目标位置。
- 一个盒子只能有一个定时器,这样的话,不会出现定时器冲突;
- 将定时器本身绑定成为盒子的一个属性,不会和其它盒子定时器产生冲突
<head>
<meta charset="UTF-8">
<title>匀速运动</title>
<style type="text/css">
body{
margin:0;
padding:0;
}
.box1{
margin:0;
position: relative;
}
.box2{
width: 100px;
height: 100px;
background-color: pink;
position: absolute;
}
.box3{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
margin-top: 130px;
}
</style>
</head>
<body>
<div class="box1">
<!--匀速运动-->
<button>匀动到200</button>
<button style="left: 50px">匀动到400</button>
<div class="box2"></div>
<div class="box3"></div>
</div>
<script>
var btn200 = document.getElementsByTagName("button")[0];
var btn400 = document.getElementsByTagName("button")[1];
var box2 = document.getElementsByTagName("div")[1];
var box3 = document.getElementsByClassName("box3")[0];
btn200.onclick = function () {
animation(box2,200);
};
btn400.onclick = function () {
animation(box3,400);
};
function animation(ele,distance) {
//1.使用定时器之前必须先清除,排除多次点击越来越快的bug
clearInterval(ele.timer); //将定时器作为元素的属性,这样一个盒子绑定一个自己的定时器,排除了其它盒子定时器的干扰
//2.为了能让div可以从后往前走,要先进行判断目标位置和当前位置的大小,如果目标位置大,步进就正,否则就负
var speed = distance>box2.offsetLeft?10:(-10);
ele.timer = setInterval(function () {
var val = distance - ele.offsetLeft; //此句位置至关重要,不能和下一句倒换位置,必须要先获取目标位置和当前位置的距离
ele.style.left = ele.offsetLeft + speed + "px"; //此时盒子会进行运动
//3.到达目标位置后,再次点击会出现抖动现象。解决方案,判断目标位置和当前位置距离是否小于步进,如果小于就让两者相等,并立刻清除定时器
if (Math.abs(val)<Math.abs(speed)){
ele.style.left = distance + "px";
clearInterval(ele.timer);
}
},30);
}
</script>
</body>
- 练习:
- 滑动轮播;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>练习</title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.box{
border: 1px solid #999;
width: 490px;
height: 170px;
margin: 60px auto 0;
padding:5px;
}
.inner{
position: relative;
width: 490px;
height: 179px;
overflow: hidden;
}
ul{
width: 500%;
position: absolute;
}
li{
list-style: none;
float: left;
}
.square{
position: absolute;
right: 10px;
top: 140px;
}
.square span{
display: inline-block;
width: 18px;
height: 18px;
background-color: #aaa;
text-align: center;
line-height: 18px;
cursor: pointer;
}
.inner .current{
background-color: darkorange;
}
</style>
</head>
<body>
<div class="box">
<div class="inner">
<ul>
<li>![](images/01.jpg)</li>
<li>![](images/02.jpg)</li>
<li>![](images/03.jpg)</li>
<li>![](images/04.jpg)</li>
<li>![](images/05.jpg)</li>
</ul>
<div class="square">
<span class="current">1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
</div>
</div>
</div>
<script>
window.onload = function () {
//获取事件源和相关元素
var inner = document.getElementsByClassName("inner")[0];
var spans = inner.children[1].children;
var ul = inner.children[0];
//获取窗口宽度
var scrollWidth = inner.offsetWidth;
for(var i=0; i<spans.length; i++){
spans[i].index = i;
spans[i].onmouseover = function () {
//使用排它思想点亮盒子
for(var j=0; j<spans.length; j++){
spans[j].className = "";
}
this.className = "current";
//移动盒子
console.log(ul);
animation(ul,-this.index*scrollWidth);
}
}
function animation(ele,target) {
clearInterval(ele.timer);
var speed = target>ele.offsetLeft ? 10:-10;
ele.timer = setInterval(function () {
var val = target - ele.offsetLeft;
ele.style.left = ele.offsetLeft + speed + "px";
if (Math.abs(val)<Math.abs(speed)){
ele.style.left = target + "px";
clearInterval(ele.timer);
}
},1);
}
};
</script>
</body>
</html>
- 左右焦点图;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>练习</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
width: 490px;
height: 170px;
margin: 60px auto;
border: 1px solid #aaa;
padding: 5px;
}
.inner{
width: 490px;
height: 170px;
position: relative;
overflow: hidden;
}
ul{
width: 500%;
position: absolute;
}
li{
list-style: none;
float: left;
}
.rl{
display: none;
}
.rl span{
position: absolute;
width: 30px;
height: 30px;
top: 70px;
color: #fff;
font-size: 30px;
line-height: 30px;
text-align: center;
background: #000 ;
left: 10px;
cursor: pointer;
opacity: 0.7;
}
.rl .right{
right: 10px;
left: auto;
}
</style>
</head>
<body>
<div class="box">
<div class="inner">
<ul>
<li>![](images/01.jpg)</li>
<li>![](images/02.jpg)</li>
<li>![](images/03.jpg)</li>
<li>![](images/04.jpg)</li>
<li>![](images/05.jpg)</li>
</ul>
<div class="rl">
<span class="left"><</span>
<span class="right">></span>
</div>
</div>
</div>
<script>
window.onload = function () {
//1.获取事件源及相关元素
var box = document.getElementsByClassName("box")[0];
var inner = document.getElementsByClassName("inner")[0];
var ul = document.getElementsByTagName("ul")[0];
var rl = document.getElementsByClassName("rl")[0];
var left = document.getElementsByClassName("left")[0];
var right = document.getElementsByClassName("right")[0];
//获取窗口宽度
var scrollW = inner.offsetWidth;
//2.左右按钮的显示和隐藏
box.onmouseover = function () {
rl.style.display = "block";
};
box.onmouseout = function () {
rl.style.display = "none";
};
//3.点击左右按钮
//定义一个计数器
var index = 0;
//点击左边按钮
left.onclick = function () {
index --;
//如果现实第一个图片时,再点击左边按钮时仍让其显示第一个图片
if (index < 0){
index = 0;
}
animation(ul,- index * scrollW);
};
//点击右边按钮
right.onclick = function () {
index ++;
//如果当前图片已经是最后一个,再点击右边按钮时始终让它展示最后一个
if (index > ul.children.length - 1){
index = ul.children.length - 1;
}
animation(ul,- index * scrollW)
};
//动画封装
function animation(ele,target) {
//清除定时器
clearInterval(ele.timer);
//设置步进大小
var speed = target>ele.offsetLeft ? 10:-10;
//设置定时器
ele.timer = setInterval(function () {
//先获取元素目标位置和当前位置的距离val
var val = target - ele.offsetLeft;
ele.style.left = ele.offsetLeft + speed + "px";
//如果val小于步进,就使元素位置等于目标位置,并清除定时器
if (Math.abs(val) < Math.abs(speed)){
ele.style.left = target + "px";
clearInterval(ele.timer);
}
},10);
}
}
</script>
</body>
</html>
- 带有定时器的轮播图。
缓动(重点
)
现象:开始走很快,越走越慢,步长越来越小,类似电梯停止。
好处:
有非常逼真的缓动效果,实现的动画效果更细腻;
如果不清除定时器,物体永远跟着目标在移动。
缓动动画公式:
动画原理 = 盒子位置 + 步长(步长越来越小);
盒子位置 = 盒子本身位置+(目标位置-盒子本身位置)/ 10;
公式:position = position + (target - position) / 10;
<body>
<button class="animate1">缓动到400</button>
<div class="huanDong"></div>
<script>
var btn = document.getElementsByClassName("animate1")[0];
var div1 = document.getElementsByClassName("huanDong")[0];
btn.onclick = function () {
var timer = setInterval(function () {
div1.style.left = div1.offsetLeft + (400 - div1.offsetLeft) / 10 + "px";
if (div1.offsetLeft == 400){
clearInterval(timer);
}
},30);
};
</script>
</body>
但是有个现象,动画会永远执行下去,不会停止。举个例子:把一桶水,倒进另一通,每次倒一半,永远倒不完;还有个原因就是
offsetLeft
会将获取值四舍五入
之后再进行计算。疑问:
原理:数学算法。其他运动形式其他算法。
为什么是10?:更符合我们的计算,逻辑,审美,人体工程学。
(实际工作中,领导给我们什么技术,我们就直接用,空余时间研究源码和原理)。
动画封装问题:
小数只能给定样式,最好不要参与计算。(offsetLeft会将获取值四舍五入取整后计算);
如果正向运动,步长是大于0;如果反向运动,步长就小于0。大于0向上取整,小于0向下取整。大于0的时候向上取整能够取到1,小于零时向下取整才能取到-1(会在9和-9距离的时候出现问题)。
<body>
<button class="bigger">缓动到400</button>
<button class="smaller">缓动到200</button>
<button class="zero">缓动到0</button>
<div class="huanDong"></div>
<script>
var btn1 = document.getElementsByClassName("bigger")[0];
var btn2 = document.getElementsByClassName("smaller")[0];
var btn3 = document.getElementsByClassName("zero")[0];
var div1 = document.getElementsByClassName("huanDong")[0];
btn1.onclick = function () {
animation(div1,400);
};
btn2.onclick = function () {
animation(div1,200);
};
btn3.onclick = function () {
animation(div1,0);
};
function animation(ele,target) {
//清除定时器
clearInterval(ele.timer);
ele.timer = setInterval(function () {
//计算步长
var step = (target - ele.offsetLeft) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
//移动位置
ele.style.left = ele.offsetLeft + step + "px";
//如果距离小于步长就将目标位置赋值给盒子,并清除定时器
if (Math.abs(target - ele.offsetLeft)<=Math.abs(step)){
ele.style.left = target + "px";
clearInterval(ele.timer);
}
},30);
}
</script>
</body>
- 案例:
- 筋斗云(光标移动到对应标签时,筋斗云图片也移动到对应位置,在没有点击的情况下如果移开光标筋斗云到最初位置;如果点击了某个标签,移开光标时,筋斗云仍然停留在点击的标签处)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>筋斗云练习</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
background-color: rgba(0,0,0,0.2);
}
.tab{
width: 600px;
height: 42px;
border-radius: 8px;
background: #fff url("images/wifi.png") right center no-repeat;
margin: 160px auto;
position: relative;
}
ul{
list-style: none;
position: absolute;
}
li{
float: left;
width: 83px;
height: 42px;
text-align: center;
line-height: 42px;
cursor: pointer;
}
span[class=cloud]{
position: absolute;
width: 83px;
height: 42px;
background: url("images/cloud.gif");
}
</style>
</head>
<body>
<div class="tab">
<span class="cloud"></span>
<ul>
<li>家乡文化</li>
<li>沿海风光</li>
<li>文人骚客</li>
<li>特色景点</li>
<li>特产美食</li>
</ul>
</div>
<script>
//入口函数
window.onload = function () {
//获取事件源和一些相关的元素
var tab = document.getElementsByClassName("tab")[0];
var lis = document.getElementsByTagName("li");
var liW = lis[0].offsetWidth;
var cloud = document.getElementsByClassName("cloud")[0];
//书写事件代码
//定义一个计数器,移除光标和点击光标时会用到
var count = 0;
for(var i=0; i<lis.length; i++){
lis[i].index = i;
//绑定鼠标进入事件
lis[i].onmouseover = function () {
//cloudAnimate(cloud,this.index * liW);
cloudAnimate(cloud,this.offsetLeft);
};
//鼠标点击事件
lis[i].onclick = function () {
count = this.index;
cloudAnimate(cloud,count * liW);
}
}
//鼠标离开事件
tab.onmouseout = function () {
cloudAnimate(cloud,count * liW);
};
//定义动画函数
function cloudAnimate(ele,target) {
//清空定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//计算步长
var step = (target - ele.offsetLeft) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
//动画原理
ele.style.left = ele.offsetLeft + step + "px";
//如果距离小于等于步长,就将目标位置直接赋值,并清除定时器
if (Math.abs(target - ele.offsetLeft) <= Math.abs(step)){
ele.style.left = target + "px";
clearInterval(ele.timer);
}
},10);
}
};
</script>
</body>
</html>
冒泡
事件冒泡: 当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡;这个事件从原始元素开始一直冒泡到DOM树的最上层。(BUG)。(好比如:本来应该一人做事一人当,结果,我做错了事情,你去告诉我妈)
事件传播阶段:
事件传播的三个阶段:捕获、冒泡、目标阶段;
事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)【从上往下】;
事件冒泡阶段:事件从事件目标开始,往上冒泡直到页面的最上一级标签【从下往上】。
什么是冒泡:子元素事件被触动,父盒子的同样的事件也会被触动。
冒泡顺序:
IE6.0:div->body->html->document;
其它浏览器:div->body->html->document->window。
不是所有的事件都能冒泡,以下事件不能冒泡:blur、focus、load、unload、onmouseenter、onmouseleave。
取消冒泡就是取消这种机制。
阻止冒泡
- w3c的方法是:
- 火狐、谷歌、IE11:
event.stopPropagation()
; - IE10以下:
event.cancelBubble = true
; - 兼容代码如下:
var event = event || window.event;
if(event && event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
获取当前对象
- IE678:
event.srcElement
(事件源); - 火狐、谷歌等:
event.target
(事件源);,谁触动事件,谁就会被放进target中; - 兼容写法获取元素ID:
var event = event || window.event;
var targetId = event.target ? event.target.id:event.srcElement.id;
addEventListenner(参数1,参数2,参数3)
调用者是:事件源;
参数1:事件去掉on;
参数2 :调用的函数
参数3:可有可无。默认false,false情况下,支持冒泡,true支持捕获。
案例
-
点击空白隐藏模态框
- Document事件的绑定,无论绑定什么事件,只要事件被出发,传递过来的应该是指定的元素本身,而不是document。
-
事件委托
- 先绑定,后创建的元素(没有事件);
- 组织冒泡,组织自己向父系盒子冒泡,所有的泡冒泡到组织的位置停止向上冒泡;
- event.target是在事件被触动的时候把事件源绑定到event的target属性中。而之前的target是我们自定义的一个变量触动。
补充
获取行内式和内嵌式属性的值
行内式:
div.style.width
,只能获取行内式属性的值,有单位px
,只包含盒子的width
,不包含padding和border;内嵌式:
div.offsetWidth
,没有单位,包含width、padding、border。获取行内式和内嵌式属性的值:
window.getComputedStyle(div,null)
获取到的值是对象类型:
var w = window.getComputedStyle(div,null).width;
var color = window.getComputedStyle(div, null)["backgroundColor"];
- 获取到的值有单位`px`,只包含`width`,不包含padding和border;
-
div.currentStyle.width
只支持IE678:
console.log(div.currentStyle.width);
console.log(div.currentStyle.padding);
- 兼容方式获取元素某个样式
function getStyle(ele, attr) {
if(window.getComputedStyle){
return window.getComputedStyle(ele,null).attr;
}else {
return ele.currentStyle[attr];
}
}
缓动的高级封装
单个属性封装
- 利用通过兼容方式获取元素某个属性的值:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>缓动封装-单个属性</title>
<style>
div{
width: 100px;
height: 100px;
border: 5px solid #ddd;
margin-top: 10px;
background-color: pink;
position: absolute;
}
</style>
</head>
<body>
<button>缓动到400</button>
<button>长度变成300</button>
<div></div>
<script>
//入口函数
window.onload = function () {
//获取事件源
var btns = document.getElementsByTagName("button");
var area = document.getElementsByTagName("div")[0];
//绑定事件
btns[0].onclick = function () {
animate(area,"left",400);
};
btns[1].onclick = function () {
animate(area,"width",300);
};
//缓动动画封装
function animate(ele,attr,target) {
//获取元素属性的值
var currentP = parseInt(getStyle(ele,attr)) || 200;
//清除定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//计算步长
var step = (target - currentP) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
//动画原理
currentP = currentP + step;
ele.style[attr] = currentP + "px";
//清除定时器
if (Math.abs(target - currentP) <= Math.abs(step)){
ele.style[attr] = target + "px";
clearInterval(ele.timer);
}
},30);
}
//获取某个属性的值
function getStyle(ele, attr) {
if (window.getComputedStyle){
return window.getComputedStyle(ele,null)[attr];
}else {
return ele.currentStyle[attr];
}
}
}
</script>
</body>
</html>
多个属性封装
- 单次运动:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多个属性</title>
<style>
div{
width: 100px;
height: 100px;
position: absolute;
right: 0;
background-color: palevioletred;
border: 5px solid #ccc;
}
</style>
</head>
<body>
<button>点击运动</button>
<div></div>
<script>
window.onload = function () {
//获取事件源和相关元素
var btn = document.getElementsByTagName("button")[0];
var div = document.getElementsByTagName("div")[0];
//绑定事件
btn.onclick = function () {
//通过JSON修改盒子多个属性的值
var json = {"left":200,"width":200,"height":200,"top":50};
animate(div,json);
};
//封装动画
function animate(ele,json) {
//清除定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//设置一个标志,记录是否符合清除定时器的条件
var bool = true;
//遍历json
for (var k in json){
//获取元素属性值
var currentP = parseInt(getStyle(ele,k)) || 200;
//计算步长
var step = (json[k] - currentP) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
currentP = currentP + step;
ele.style[k] = currentP + "px";
//记录状态
if (Math.abs(json[k] - currentP) > Math.abs(step)){
bool = false;
}
}
//判断是否符合清除定时器的条件
if (bool){
for (var k in json){
ele.style[k] = json[k] + "px";
}
clearInterval(ele.timer);
}
},30);
}
//获取元素属性值
function getStyle(ele, attr) {
if (window.getComputedStyle){
return window.getComputedStyle(ele,null)[attr];
}else {
return ele.currentStyle[attr];
}
}
}
</script>
</body>
</html>
- 往返运动:方法一
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多个属性</title>
<style>
div{
width: 100px;
height: 100px;
position: absolute;
left: 30px;
top: 40px;
background-color: palevioletred;
border: 5px solid #ccc;
}
</style>
</head>
<body>
<button>点击运动</button>
<div></div>
<script>
window.onload = function () {
//获取事件源和相关元素
var btn = document.getElementsByTagName("button")[0];
var div = document.getElementsByTagName("div")[0];
//绑定事件
btn.onclick = function () {
//通过JSON修改盒子多个属性的值
var json1 = {"width":200,"height":200,"left":100,"top":150};
var json2 = {"width":100,"height":100,"left":30,"top":40};
animate(div,json1,json2);
};
//封装动画
function animate(ele,json,fn) {
//清除定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//设置一个标志,记录是否符合清除定时器的条件
var bool = true;
//遍历json
for (var k in json){
//获取元素属性值
var currentP = parseInt(getStyle(ele,k)) || 200;
//计算步长
var step = (json[k] - currentP) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
currentP = currentP + step;
ele.style[k] = currentP + "px";
//记录状态
if (Math.abs(json[k] - currentP) > Math.abs(step)){
bool = false;
}
}
//判断是否符合清除定时器的条件
if (bool){
for (var k in json){
ele.style[k] = json[k] + "px";
}
clearInterval(ele.timer);
if (fn){
animate(ele,fn);
}
}
},30);
}
//获取元素属性值
function getStyle(ele, attr) {
if (window.getComputedStyle){
return window.getComputedStyle(ele,null)[attr];
}else {
return ele.currentStyle[attr];
}
}
}
</script>
</body>
</html>
- 往返运动:方法二
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多个属性</title>
<style>
div{
width: 100px;
height: 100px;
position: absolute;
left: 30px;
top: 40px;
background-color: palevioletred;
border: 5px solid #ccc;
}
</style>
</head>
<body>
<button>点击运动</button>
<div></div>
<script>
window.onload = function () {
//获取事件源和相关元素
var btn = document.getElementsByTagName("button")[0];
var div = document.getElementsByTagName("div")[0];
//绑定事件
btn.onclick = function () {
//通过JSON修改盒子多个属性的值
var json1 = {"width":200,"height":200,"left":100,"top":150};
var json2 = {"width":100,"height":100,"left":30,"top":40};
// animate(div,json1,json2);
animate(div,json1,function () {
animate(div,json2,function () {
animate(div,json1,function () {
animate(div,json2,function () {
animate(div,json1);
});
});
});
});
};
//封装动画
function animate(ele,json,fn) {
//清除定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//设置一个标志,记录是否符合清除定时器的条件
var bool = true;
//遍历json
for (var k in json){
//获取元素属性值
var currentP = parseInt(getStyle(ele,k)) || 200;
//计算步长
var step = (json[k] - currentP) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
currentP = currentP + step;
ele.style[k] = currentP + "px";
//记录状态
if (Math.abs(json[k] - currentP) > Math.abs(step)){
bool = false;
}
}
//判断是否符合清除定时器的条件
if (bool){
for (var k in json){
ele.style[k] = json[k] + "px";
}
clearInterval(ele.timer);
if (fn){
// animate(ele,fn);
fn();
}
}
},30);
}
//获取元素属性值
function getStyle(ele, attr) {
if (window.getComputedStyle){
return window.getComputedStyle(ele,null)[attr];
}else {
return ele.currentStyle[attr];
}
}
}
</script>
</body>
</html>
案例:
- 手风琴;
- 360开机动画。
缓动框架存在的问题:
- 有很多属性依然无法获取值和赋值:
- border-radius:1px 2px 3px 4px;
- 渲染有问题,可以通过拆解来解决,解决方法如下:
div.style.borderBottomLeftRadius = "30px";
div.style.borderTopRightRadius = "30px";
-
opacity:0.5;
(没有单位的)- 火狐、谷歌、IE9+,
opacity:0.5;
,内容一起透明,取值范围:0~1
,但是赋值的时候一般用百分制,但最后赋值时候再除以一百,因为小数有精度问题,防止中途需要运算,使误差变大; - IE678(一般不研究),
filter:alpha(opacity=50);
,取值范围:0~100
。
- 火狐、谷歌、IE9+,
- background:rgba(0,0,0,0.3);
-
z-index:1;
...等等。
增加了透明度和层级之后的封装
/**
* Created by YJW on 2017/8/11.
*/
//匀速运动动画
function conSpeedAnimate(ele,distance) {
//1.使用定时器之前必须先清除,排除多次点击越来越快的bug
clearInterval(ele.timer); //将定时器作为元素的属性
//2.为了能让div可以从后往前走,要先进行判断目标位置和当前位置的大小,如果目标位置大,步进就正,否则就负
var speed = distance>ele.offsetLeft ? 10:-10;
ele.timer = setInterval(function () {
var val = distance - ele.offsetLeft; //测试发现:此句位置至关重要,不能和下一句倒换位置
ele.style.left = ele.offsetLeft + speed + "px";
//3.到达目标位置后,再次点击会出现抖动现象。解决方案,判断目标位置和当前位置距离是否小于步进,如果小于就让两者相等,并立刻清除定时器
if (Math.abs(val)<Math.abs(speed)){
ele.style.left = distance + "px";
clearInterval(ele.timer);
}
},10);
}
//缓动动画
function slowMovingAnimateX(ele,targetX) {
//清空定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//计算步长
var stepX = (targetX - ele.offsetLeft) / 10;
stepX = stepX>0 ? Math.ceil(stepX):Math.floor(stepX);
//动画原理
ele.style.left = ele.offsetLeft + stepX + "px";
//如果距离小于等于步长,就将目标位置直接赋值,并清除定时器
if (Math.abs(targetX - ele.offsetLeft) <= Math.abs(stepX)){
ele.style.left = targetX + "px";
clearInterval(ele.timer);
}
},10);
}
function slowMovingAnimateY(ele,targetY) {
//清空定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//计算步长
var stepY = (targetY - ele.offsetTop) / 10;
stepY = stepY>0 ? Math.ceil(stepY):Math.floor(stepY);
//动画原理
ele.style.top = ele.offsetTop + stepY + "px";
//如果距离小于等于步长,就将目标位置直接赋值,并清除定时器
if (Math.abs(targetY - ele.offsetTop) <= Math.abs(stepY)){
ele.style.top = targetY + "px";
clearInterval(ele.timer);
}
},10);
}
//对scroll()函数进行封装
function scroll(){
//如果window.pageYOffset存在,返回值为0~无穷大,如果不存在返回undefined。
if (window.pageYOffset !== undefined){
var json = {
"top":window.pageYOffset,
"left":window.pageXOffset
}
return json;
} else if (document.compatMode === CSS1Compat) {
return {
"top":document.documentElement.scrollTop,
"left":document.documentElement.scrollLeft
}
} else {
return {
"top":document.body.scrollTop,
"left":document.body.scrollLeft
}
}
}
// function scroll() {
// return {
// "top" : window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop,
// "left" : window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft
// }
// }
//对clientWidth进行封装(获取盒子/body、html可视区域的宽高)
function client() {
if (window.innerWidth !== undefined){
return{
"width":window.innerWidth,
"height":window.innerHeight
}
}else if (document.compatMode === "CSS1Compat"){
return{
"width":document.documentElement.clientWidth,
"height":document.documentElement.clientHeight
}
}else {
return{
"width":document.body.clientWidth,
"height":document.body.clientHeight
}
}
}
//盒子的隐藏和显示
function show(div) {
div.style.display = "block";
}
function hide(div) {
div.style.display = "none";
}
//获取鼠标在盒子中的位置
function positionXY(event, div) {
//获取鼠标的位置
event = event || window.event;
var pagex = event.pageX || event.clientX + scroll().left;
var pagey = event.pageY || event.clientY + scroll().top;
//获取鼠标在盒子中的位置,并让鼠标处在遮盖中间位置
var positionX = pagex - content.offsetLeft;
var positionY = pagey - content.offsetTop;
return{
"positionX":positionX,
"positionY":positionY
}
}
//缓动动画高级封装--单个属性
function animate(ele,attr,target) {
//获取元素属性的值
var currentP = parseInt(getStyle(ele,attr)) || 0;
//清除定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//计算步长
var step = (target - currentP) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
//动画原理
currentP = currentP + step;
ele.style[attr] = currentP + "px";
//清除定时器
if (Math.abs(target - currentP) <= Math.abs(step)){
ele.style[attr] = target + "px";
clearInterval(ele.timer);
}
},30);
}
//封装缓动动画----设置多个属性
function animate(ele,json,fn) {
//清除定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//设置一个标志,记录是否符合清除定时器的条件
var bool = true;
//遍历json
for (var k in json){
//获取元素属性值
var currentP = parseInt(getStyle(ele,k)) || 0;
//计算步长
var step = (json[k] - currentP) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
currentP = currentP + step;
ele.style[k] = currentP + "px";
//记录状态
if (Math.abs(json[k] - currentP) > Math.abs(step)){
bool = false;
}
}
//判断是否符合清除定时器的条件
if (bool){
for (var k in json){
ele.style[k] = json[k] + "px";
}
clearInterval(ele.timer);
if (fn){
// animate(ele,fn);
fn();
}
}
},30);
}
//缓动动画封装----增加了透明度和层级
function animate(ele,json,fn) {
//清除定时器
clearInterval(ele.timer);
//设置定时器
ele.timer = setInterval(function () {
//设置一个标志,记录是否符合清除定时器的条件
var bool = true;
//遍历json
for (var k in json){
//获取元素属性值
var currentP;
// 如果是opacity获取值之后需要进行特殊处理
if (k === "opacity"){
currentP = getStyle(ele,k)*100 || 10;
console.log(getStyle(ele,k));
}else {
console.log(getStyle(ele, k) + " -- " + k);
currentP = parseInt(getStyle(ele,k)) || 0;
}
//计算步长
var step = (json[k] - currentP) / 10;
step = step>0 ? Math.ceil(step):Math.floor(step);
currentP = currentP + step;
//如果是opacity需要特殊赋值处理
if (k === "opacity"){
ele.style[k] = currentP / 100;
//兼容IE678
ele.style["filter"] = "alpha(opacity=" + currentP + ")";
}else if (k === "z-index"){
ele.style[k] = json[k];
}else {
ele.style[k] = currentP + "px";
}
//记录状态
if (Math.abs(json[k] - currentP) > Math.abs(step)){
bool = false;
}
}
//判断是否符合清除定时器的条件
if (bool){
for (var k in json){
ele.style[k] = json[k] + "px";
}
clearInterval(ele.timer);
if (fn){
fn();
}
}
},30);
}
//兼容方式获取元素属性值
function getStyle(ele, attr) {
if(window.getComputedStyle){
return window.getComputedStyle(ele,null).attr;
}else {
return ele.currentStyle[attr];
}
}
案例
- 旋转轮播图;