Animation

匀速动画

匀速运动(横向)

1.初始化速度变量
2.开启定时器
(1)获取当前值
(2)改变当前值:当前值+速度
(3)将改变后的值赋值给元素的样式
(4)当改变后的值大于等于目标值,清除定时器,同时将改变后的值改成目标值。这一步应该在赋值给样式之前

 //下面若无重写,均采用这个css和html
 #katsuki{position: absolute;left: 0;top: 0;}
<img src="../img/katsuki.jpg" id="katsuki">
<script>
	document.addEventListener('DOMContentLoaded',function(){
		var katsuki = document.querySelector('#katsuki');
		//初始化速度变量
		var speed = 10;
		//开启定时器
		var timer = setInterval(function(){
			//获取元素当前值,一般用window.getComputedStyle
			var x = katsuki.offsetLeft;
			//改变当前值:当前值+速度
			x += speed;
			//当改变后的值大于等于目标值,清除定时器,
			//同时将改变后的值改成目标值。这一步应该在赋值给样式之前
			if(x > window.innerWidth - katsuki.offsetWidth){
				x = window.innerWidth - katsuki.offsetWidth;
				clearInterval(timer);
			}
			//将改变后的值赋值给元素的样式
			katsuki.style.left = x + 'px';
		},50)
	})
</script>

加速运动

document.addEventListener('DOMContentLoaded',function(){
	var katsuki = document.querySelector('#katsuki');
	var speed = 10;
	var timer = setInterval(function(){
		var x = katsuki.offsetLeft;
		x += speed;
		//在匀速的基础上,这里设置速度增加
		speed += 2;
		if(x > window.innerWidth - katsuki.offsetWidth){
			x = window.innerWidth - katsuki.offsetWidth;
			clearInterval(timer);
		}
		katsuki.style.left = x + 'px';
	},50)
})

减速运动

document.addEventListener('DOMContentLoaded',function(){
	var katsuki = document.querySelector('#katsuki');
	var speed = 60;
	var timer = setInterval(function(){
		var x = katsuki.offsetLeft;
		x += speed;
		//在匀速的基础上,这里设置速度减少
		speed -= 2;
		//速度减为负数不清定时器,图片就会倒退
		if(speed < 0){
			clearInterval(timer);
		}
		katsuki.style.left = x + 'px';
	},50)
})

抛物线

1.初始化速度变量(水平、垂直)
2.开启定时器
(1)获取当前值(水平、垂直)
(2)改变当前值:当前值+速度
(3)速度不断减小(垂直方向的速度)
(4)将改变后的值赋值给元素的样式
(5)当改变后的值大于等于目标值,清除定时器,同时将改变后的值改成目标值。这一步应该在赋值给样式之前

 #katsuki{position: absolute;left: 0;bottom: 0;}
document.addEventListener('DOMContentLoaded',function(){
	var katsuki = document.querySelector('#katsuki');
	//水平速度
	var xspeed = 7;
	//垂直速度
	var yspeed = 13;
	var timer = setInterval(function(){
		var x = katsuki.offsetLeft;
		var y = katsuki.offsetTop;
		x += xspeed;
		y -= yspeed;
		//垂直方向速度减少
		yspeed -= 0.2;
		if(y > window.innerHeight - katsuki.offsetHeight){
			//将改变后的值改成目标值,防止图片超出浏览器可视区域
			y = window.innerHeight - katsuki.offsetHeight;
			clearInterval(timer);
		}
		katsuki.style.left = x + 'px';
		katsuki.style.top = y + 'px';
	},50)
})

缓冲动画

关键:动态计算速度(目标值-当前值有关)
1.开启定时器
(1)获取当前值
(2)获取当前速度(目标值-当前值).
当速度大于0时,Math.ceil()
当速度小于0时,Math.floor()
避免出现减到小数一直减却减不到目标值,进行取整
(4)改变当前值:当前值+速度
(5)将改变后的值赋值给元素的样式
(6)当改变后的值等于目标值,清除定时器
若事件里面开启定时器,记得开启定时器先清除定时器

//返回顶部缓冲
body{height: 3000px;}
#katsuki{
     width: 100px;
     height: 100px;
     position:fixed;
     right : 20px;
     bottom: 20px;
}
document.addEventListener('DOMContentLoaded',function(){
	var katsuki = document.querySelector('#katsuki');
	katsuki.onclick = function(){
		//避免多次点击启动多个定时器,进入就执行清除
		/*
		以节点进行绑定:katsuki.timer,是为了保证清除的是同一个timer,
		点击多次有多个执行函数,若每次定义var timer,timer不是同一个,无法清除
		*/
		clearInterval(katsuki.timer);
		katsuki.timer = setInterval(function(){
			//获取当前值
			var y = window.scrollY;
			//动态计算速度(目标值-当前值)除10是避免速度过快
			var speed = Math.floor((0-y)/10);
			y += speed
			//设置window滚动条位置
			window.scrollTo(0,y);
			//取整,必定会减为0,直接判断等于0时
			if(y == 0){
				clearInterval(katsuki.timer);
			}
		}50)
	}
})

动画的封装

缓冲动画

1.开启定时器
(1)获取当前值
(2)获取当前速度(目标值-当前值).
当速度大于0时,Math.ceil()
当速度小于0时,Math.floor()
(3)改变当前值:当前值+速度
(4)将改变后的值赋值给元素的样式
(5)当改变后的值等于目标值,清除定时器
备注: 事件开启定时器之前,一定要记得先清除已存在的定时器。

/**
 * [缓冲动画]
 * @param  {Element} ele  [获取动画的元素]
 * @param  {String} attr [ele的属性名]
 * @param {Number} target [动画的目标值]
 * @param {Number} time [定时器时间(毫秒)]
 */
function animate(ele,attr,target,time){
 	clearInterval(ele.timer);
 	ele.timer = setInterval(function(){
 		var current = window.getComputedStyle(ele)[attr];//200px,180deg,0.5
 		//提取单位
 		var unit = current.match(/[a-z]+$/);
 		//判断有无单位并赋值
 		unit = unit? unit[0] : '';
 		//取到数值,不用parseInt是考虑到可能小数
 		current = parseFloat(current);
 		//计算缓冲速度
 		var speed = (target-current)/10
 		if(attr === 'opacity'){
 			//针对图片淡入淡出使用opacity时
 			speed = speed>0? 0.01 : -0.01;
 		}else{
 			//speed取整,避免速度过小或为0
 			speed = speed>0? Math.ceil(speed) : Math.floor(speed);
 		}
 		current += speed;
 		if(current == target){
            clearInterval(ele.timer);
            //避免超出目标值
            current = target;
        }
 		ele.style[attr] = current + unit;
 	},time)
 }

缓冲动画完善

缓冲动画(改进)
1.定时器名字根据css属性进行命名,从而保证多个定时器赋值给的变量名不同,不会发生覆盖。
2.在一个动画函数里面,可以定义多个css属性同时改变
参数变成对象{attr:target}
for…in遍历对象,拿到每个attr及对应target值
利用let,将attr、target的值保留在当前的块级作用域
利用函数的形参,将attr、target的值存在局部作用域。
3.需求:所有动画执行完毕后,进行一堆操作。
(1)在清除定时器后再执行这堆操作,会出现执行多次的问题
统计出attr的个数,每次清除定时器就对个数进行–,直到为0,代表所有动画执行完毕。
(2) 封装动画函数结束后,别人要做什么,我不知道。所以只能帮你执行。你需要把你要做的东西封装成函数,传参给我
别人不一定会传递回调函数,要判断。

/**
 * [缓冲动画]
 * @param  {Element} ele  [获取动画的元素]
 * @param  {Object} obj [ele的属性对象]
 * 		attr     {Sting}       属性名
 *  	target   {Number}      动画的目标值
 * @param {Number} time [定时器时间(毫秒)]
 * @param {function} fn [函数]
 */
 function animate(ele,obj,time,fn){
	//3为实现所有动画执行完毕后,进行fn操作,首先存储执行次数
	var count = 0;
	//对象遍历
	for(var key in obj){
		count ++;
		//2.1利用let,将attr、target的值保留在当前的块级作用域
		let attr = key;
		let target = obj[key];
		/*2.2利用函数的形参,将attr、target的值存在局部作用域
		var attr = key;
		var target = attr[key];
		然后将下面代码封装成函数,传参,假若封装成show
		show(attr,target);*/
		clearInterval(ele[attr + "Timer"]);
 		//1定时器赋值给的变量名不同,不会发生覆盖,实现多个动画进行
 		ele[attr + "Timer"] = setInterval(function(){
	 		var current = window.getComputedStyle(ele)[attr];
	 		console.log(current);
	 		var unit = current.match(/[a-z]+$/);
	 		unit = unit? unit[0] : '';
	 		current = parseFloat(current);
	 		console.log(current);
	 		var speed = (target-current)/10;
	 		if(attr === 'opacity'){
	 			speed = speed>0? 0.01 : -0.01;
	 		}else{
	 			speed = speed>0? Math.ceil(speed) : Math.floor(speed);
	 		}
	 		current += speed;
	 		if(current == target){
	            clearInterval(ele[attr + "Timer"]);
	            current = target;
	            //3当count减为0时,即为最后一个动画执行完毕
	            count --;
	            if(count == 0 && fn && typeof(fn) == "function"){
	            	fn();
	            }
        	}
 			ele.style[attr] = current + unit;
 		},time)
	}
 }

匀速动画

1.初始化速度变量
2.开启定时器
(1)获取当前值
(2)改变当前值:当前值+速度
(3)将改变后的值赋值给元素的样式
(4)当改变后的值大于等于目标值,清除定时器,同时将改变后的值改成目标值。这一步应该在赋值给样式之前

/**
 * [匀速动画]
 * @param  {String} speed [速度值]
 * @param  {Element} ele  [获取动画的元素]
 * @param  {String} attr [ele的属性名]
 * @param {Number} target [动画的目标值]
 * @param {Number} time [定时器时间(毫秒)]
 */
function linearAnimate(speed,ele,attr,target,time){
	clearInterval(ele.timer);
	ele.timer = setInterval(function(){
		//获取当前值
		var current = window.getComputedStyle(ele)[attr];
		//提取单位
 		var unit = current.match(/[a-z]+$/);
 		//判断有无单位并赋值
 		unit = unit? unit[0] : '';
 		//取到数值,不用parseInt是考虑到可能小数
 		current = parseFloat(current);
 		//改变当前值
 		current += speed;
 		ele.style[attr] = current + unit;
 		if(speed>0 && current >= target || speed<0 && current <= target){
			current = target;
        	clearInterval(ele.timer);
		}
	})
}

瀑布流

1)计算当前容器能容纳多少列
列数 = parseInt(容器宽度/图片宽度)
2)计算水平间隔
间隔 = 容器宽度%图片宽度/(列数+1)
3)创建一个数组pos
用来保存第一行每列图片左上角坐标(left,top)
4)遍历所有图片,往容器里添加图片
遍历数组pos,查找最小top值,然后更新当前top值
top = top + vgap + 图片高度

document.addEventListener('DOMContentLoaded',function(){
	// 获取元素
	let wrap = document.querySelector('#wrap');
	let items = wrap.children;
	// 获取单个图片宽度
	let itemWidth = items[0].offsetWidth;
	waterfall();
	// 窗口大小改变,自适应
	window.onresize = waterfall;
	function waterfall(){
		// 获取容器宽度(考虑滚动条宽度)
	    let containerWidth = wrap.clientWidth-17;
	    //  1)计算当前容器能容纳多少列
	    let len = Math.floor(containerWidth/itemWidth);
	    // 2)计算间隔
	    let gap = containerWidth%itemWidth/(len+1);
	    //  3)创建一个数组pos
	    //  用于存放左上角坐标(小红点)
	    let pos = [];
	    for(let i=0;i<len;i++){
	        pos[i] = {
	            top: gap,
	            left:itemWidth*i + gap*(i+1)
	        }
	    }
	    console.log(pos);
	    // 开始定位图片
	    // 4)遍历所有图片,设置top,left
	    for(let i=0;i<items.length;i++){
	        // 找出当前图片
	        let img = items[i].querySelector('img');
	        // 图片如果被浏览器缓存,图片的属性complete为true
	        if(img.complete){
	            showImg();
	        }else{
	            // 等待图片加载完成
	            img.onload = showImg;
	        }
	        function showImg(){
	            // 找出最小top值
	            // 假设第一个最小
	            let minIdx = 0;
	            let min = pos[minIdx].top;
	            for(let j=1;j<pos.length;j++){
	                // 判断是否存在更小的top值
	                if(pos[j].top < min){
	                    min = pos[j].top;
	                    // 更新索引值
	                    minIdx = j;
	                }
	            }
	            // items[i].style.left = pos[minIdx].left + 'px';
	            // items[i].style.top = pos[minIdx].top + 'px';
	            animate(items[i],{left:Math.round(pos[minIdx].left),top:Math.round(pos[minIdx].top)});
	            // 定位后,更新top值
	            pos[minIdx].top += gap + items[i].offsetHeight;
	        }	
	    }
	}
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值