先上代码
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<style>
html,body{background-color:#282923;height:100%;width:100%;font-size:65.5%;margin:0;padding:0;}
.snow{
color:white;
animation:rotes 3s infinite linear;
}
@keyframes rotes{
100%{
transform:rotate3d(1,-1,1,720deg);
}
}
</style>
</head>
<body>
</body>
</html>
<script type="text/javascript">
snow = function(){
this.body = document.body;
this.millisec = 30;//下一朵雪花生成的速度
this.timer;
this.winwidth = window.innerWidth;
this.winHeight = window.innerHeight;
//创建并返回 一个雪花对象
this.create = function(){
snowborder = document.createElement('div');
snow = document.createElement('div');
snowborder.appendChild(snow);
snowborder.style.position='absolute';
//雪花的属性
snow.classList.add('snow');
snow.innerHTML = '❉';
return snowborder;
}
//开始下雪效果 var 定义变量为局部,为了指定当前的雪花元素
this.play = function(){
this.body.style.cssText=`transform-style:preserve-3d;
transform:perspective(50rem);`;
var that = this; //将this保存在that内,因为 闭包函数内和外部不联系
this.timer = setInterval(function(){
var snowborder = that.create();
//克隆一个雪花
var cloneSnow = snowborder.cloneNode(1);
/*开始位置*/
var startx = (that.winwidth*.95)*Math.random();
var starty = (that.winHeight*.95)*Math.random();
/*结束位置*/
var endx = (that.winwidth*.95) * Math.random();
var endy = (that.winHeight*.95) * Math.random();
var endz = (that.winHeight*.5) * Math.random();
/* 持续时间 这个时间是元素从初始化状态到最终状态所需的过渡时间,也是删除元素的时间 !!! */
var duration = parseInt(4000 + Math.random()*4000);
var fontSize = 1 + Math.random()*30;
// 开始时透明度
var startOpacity = .5+.3*Math.random();
// 结束时透明度
var endOpacity = .1;
//设置初始的雪花位置和大小
cloneSnow.style.cssText += `
transform:translate3d(${startx}px,0,${endz}px);
opacity:${startOpacity};
transition:all ${duration}ms linear;
font-size:${fontSize}px;`;
/* adding to body */
that.body.appendChild(cloneSnow);
//0.1秒后设置一下css,覆盖掉一些位置的,使得位置发送变化
setTimeout(function(){
cloneSnow.style.cssText += `
transform:translate3d(${endx}px,${endy}px,${endz}px);
opacity:${endOpacity};
`;
setTimeout(function(){
cloneSnow.remove();
},duration);//刚好是过渡效果结束的时间,把元素删除
},100);
},this.millisec);
return "play";
};
//停止下雪效果
this.stop=function(){
clearInterval(this.timer);
return 'stop';
}
}
// 实 例 化
snowObject = new snow();
snowObject.play(); //开始
// snowObject.stop(); //停止
</script>
snow类有两个主要方法
play() 开启定时器,雪花开始生成飘落
stop() 删除定时器,雪花停止生成
类的使用需要:
必要的
html,body{background-color:#282923;height:100%;width:100%;font-size:65.5%;margin:0;padding:0;}
【不是必要的】
需要定义一个动画 rotes 这是雪花飘落过程中雪花本身的动作,这里用的是旋转;可以不要
@keyframes rotes{
100%{
transform:rotate3d(1,-1,1,720deg);
}
}
定义一下.snow的样式
.snow{
color:white;
animation:rotes 3s infinite linear;
}
标题说一下主要的实现方法
- 或许你没猜到,那么这个动画效果是如何实现的呢?transition属性!!第一个定时器生成了雪花的初始状态,第二个在生成的100毫秒后给了元素一个结束状态(关键帧);第三个定时器只用了一行代码,snowClone.remove();三个定时器嵌套使用了
确定删除的属性。因为用的是嵌套,里面对元素都是用局部变量定义的,这样的话,不用给元素起id或者class,就可以确定是哪个元素了,因为一个局部区域里,只有一个雪花元素snowClone;第三个定时器选定到时间点则删除 - 3d的效果的实现:给父元素添加两个属性
transform-style:preserve-3d; //保留子元素的3d效果
transform:perspective(50rem); //屏幕离场景的距离,可以用px。rem主要是移动端用的单位;
子元素的3d移动 :
用 tranform : translate3d(x,y,z)属性;三个值不表示三个方位的位移量水平x,竖直y,垂直向屏幕是z单位可以是px,rem,等
这样做有什么好处呢?
雪花的飘落用的是translate3d属性,这属性会触发GPU加速,和positionl相比动画会更流畅
setInterval定时器只用了一个,用来生成雪花,雪花的移动和元素删除分别用了两个setTimeout定时器来完成;定时器的减少对降低了性能的开销;
效果图