经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » CSS3 » 查看文章
CSS 、JS实现浪漫流星雨动画
来源:jb51  时间:2018/11/12 10:09:09  对本文有异议

1,效果图

2,源码

HTML

  1. < body > 
  2.     < div  class = "container" > 
  3.         < div  id = "mask" > </ div > 
  4.         < div  id = "sky" > </ div > 
  5.         < div  id = "moon" > </ div > 
  6.         < div  id = "stars" > </ div > 
  7.         < div  class = "cloud cloud-1" ></ div > 
  8.         <div  class = "cloud cloud-2" > </ div > 
  9.         < div  class = "cloud cloud-3" > </ div > 
  10.     </ div > 
  11. </ body >

CSS

  1. /*  -  -  -  -  -  - 重启 -  -  -  -  -  -  */
  2.  
  3.  * {
  4.      保证金:0 ;
  5.      填充:0 ;
  6.  }
  7.  
  8.  html
  9.   body {
  10.       width100 ;
  11.      最小宽度:1000px ;
  12.      身高:100 ;
  13.      最小高度:400px ;
  14.      溢出:隐藏;
  15.  }
  16.  
  17.  / * ------------画布------------ * / 
  18.  .container {
  19.       positionrelative;
  20.      身高:100 ;
  21.  }
  22.  / *遮罩层* /
  23.  
  24.  #mask {
  25.       positionabsolute;
  26.      宽度:100 ;
  27.      身高:100 ;
  28.      backgroundrgba0,0,0,.8);
  29.      z-index900 ;
  30.  }
  31.  / *天空背景* /
  32.  
  33.  #sky {
  34.       width100 ;
  35.      身高:100 ;
  36.      background:线性渐变(rgba0,150,255,1),rgba0,150,255,.8),rgba0,150,255,.5));
  37.  }
  38.  / *月亮* /
  39.  
  40.  #moon {
  41.       positionabsolute;
  42.      上:50px ;
  43.      右:200px ;
  44.      宽度:120px ;
  45.      身高:120px ;
  46.      背景:rgba251,255,25,0.938);
  47.      border-radius50 ;
  48.      box-shadow0  0  20px  rgba251,255,25,0.5);
  49.      z-index9999 ;
  50.  }
  51.  / *闪烁星星* /
  52.  
  53.  .blink {
  54.       positionabsolute;
  55.      backgroundrgb255,255,255);
  56.      border-radius50 ;
  57.      box-shadow0  0  5px  rgb255,255,255);
  58.      不透明度:0 ;
  59.      z-index10000 ;
  60.  }
  61.  / *流星* /
  62.  
  63.  .star {
  64.       positionabsolute;
  65.      不透明度:0 ;
  66.      z-index10000 ;
  67.  }
  68.  
  69.  .star :: after {
  70.       content"" ;
  71.      显示:块;
  72.      边界:坚固;
  73.      border-width2px  0  2px  80px ;
  74.      / *流星随长度逐渐缩小* / 
  75.      border-color:透明透明透明rgba255,255,255,1);
  76.      border-radius2px  0  0  2px ;
  77.      transformrotate(-45deg);
  78.      transform-origin0  0  0 ;
  79.      盒子阴影:0  0  20px  rgba255,255,255,.3);
  80.  }
  81.  / *云* /
  82.  
  83.  .cloud {
  84.       positionabsolute;
  85.      宽度:100 ;
  86.      身高:100px ;
  87.  }
  88.  
  89.  .cloud-1 {
  90.       bottom - 100px ;
  91.      z-index1000 ;
  92.      不透明度:1 ;
  93.      变换:规模(1.5);
  94.      -webkit-transformscale1.5);
  95.      -moz-transformscale1.5);
  96.      -ms-transformscale1.5);
  97.      -o-transformscale1.5);
  98.  }
  99.  
  100.  .cloud-2 {
  101.       left - 100px ;
  102.      底部: - 50px ;
  103.      z-index999 ;
  104.      不透明度:。5 ;
  105.      变换:旋转(7deg);
  106.      -webkit-transformrotate7deg);
  107.      -moz-transformrotate7deg);
  108.      -ms-transformrotate7deg);
  109.      -o-transformrotate7deg);
  110.  }
  111.  
  112.  .cloud-3 {
  113.       left120px ;
  114.      底部: - 50px ;
  115.      z-index999 ;
  116.      不透明度:。1 ;
  117.      transformrotate(-10deg);
  118.      -webkit-transformrotate(-10deg);
  119.      -moz-transformrotate(-10deg);
  120.      -ms-transformrotate(-10deg);
  121.      -o-transformrotate(-10deg);
  122.  }
  123.  
  124.  .circle {
  125.       positionabsolute;
  126.      border-radius50 ;
  127.      背景:#fff ;
  128.  }
  129.  
  130.  .circle-1 {
  131.       width100px ;
  132.      身高:100px ;
  133.      上: - 50px ;
  134.      左:10px ;
  135.  }
  136.  
  137.  .circle-2 {
  138.       width150px ;
  139.      身高:150px ;
  140.      上: - 50px ;
  141.      左:30px ;
  142.  }
  143.  
  144.  .circle-3 {
  145.       width300px ;
  146.      身高:300px ;
  147.      上: - 100px ;
  148.      左:80px ;
  149.  }
  150.  
  151.  .circle-4 {
  152.       width200px ;
  153.      身高:200px ;
  154.      上: - 60px ;
  155.      左:300px ;
  156.  }
  157.  
  158.  .circle-5 {
  159.       width80px ;
  160.      身高:80px ;
  161.      上: - 30px ;
  162.      左:450px ;
  163.  }
  164.  
  165.  .circle-6 {
  166.       width200px ;
  167.      身高:200px ;
  168.      上: - 50px ;
  169.      左:500px ;
  170.  }
  171.  
  172.  .circle-7 {
  173.       width100px ;
  174.      身高:100px ;
  175.      上: - 10px ;
  176.      左:650px ;
  177.  }
  178.  
  179.  .circle-8 {
  180.       width50px ;
  181.      身高:50px ;
  182.      上:30px ;
  183.      左:730px ;
  184.  }
  185.  
  186.  .circle-9 {
  187.       width100px ;
  188.      身高:100px ;
  189.      上:30px ;
  190.      左:750px ;
  191.  }
  192.  
  193.  .circle-10 {
  194.       width150px ;
  195.      身高:150px ;
  196.      上:10px ;
  197.      左:800px ;
  198.  }
  199.  
  200.  .circle-11 {
  201.       width150px ;
  202.      身高:150px ;
  203.      上: - 30px ;
  204.      左:850px ;
  205.  }
  206.  
  207.  .circle-12 {
  208.       width250px ;
  209.      身高:250px ;
  210.      上: - 50px ;
  211.      左:900px ;
  212.  }
  213.  
  214.  .circle-13 {
  215.       width200px ;
  216.      身高:200px ;
  217.      上: - 40px ;
  218.      左:1000px ;
  219.  }
  220.  
  221.  .circle-14 {
  222.       width300px ;
  223.      身高:300px ;
  224.      上: - 70px ;
  225.      左:1100px ;
  226.  }

JS

  1. //流星动画 
  2. setIntervalfunction() {
  3.      const obj = addChild"#sky""div"2"star");
  4.  
  5.     forlet i = 0 ; i <obj.children.length; i ++){
  6.          const top = -50 + Math .random()* 200 + "px"
  7.             left = 200 + Math .random()* 1200 + "px"
  8.             scale = 0.3 + Math .random()* 0.5 ;
  9.         const timer = 1000 + Math .random()* 1000 ;
  10.  
  11.         obj.children [i] .style.top = top;
  12.         obj.children [i] .style.left = left;
  13.         obj.children [i] .style.transform = `scale($ {scale})` ;
  14.  
  15.         requestAnimation({
  16.             eleobj.children [i],
  17.              attr:[ "top""left""opacity" ],
  18.              值:[ 150,-150,.8 ],
  19.              timetimer
  20.              flagfalse
  21.              fnfunction() {
  22.                 requestAnimation({
  23.                     ELEobj.children [I],
  24.                      ATTR"顶""左""不透明" ],
  25.                      值:[ 150,-1500 ],
  26.                      时间:定时器,
  27.                      标志:假,
  28.                      FN:() => {
  29.                         obj.parent.removeChildobj.children [I]);
  30.                     }
  31.                 })
  32.             }
  33.         });
  34.     }
  35.  
  36. },1000);
  37.  
  38. //闪烁星星动画 
  39. setIntervalfunction() {
  40.      const obj = addChild"#stars""div"2"blink");
  41.  
  42.     forlet i = 0 ; i <obj.children.length; i ++){
  43.          const top = -50 + Math .random()* 500 + "px"
  44.             left = 200 + Math .random()* 1200 + "px"
  45.             round = 1 + Math .random()* 2 + "px" ;
  46.         const timer = 1000 + Math .random()* 4000 ;
  47.  
  48.         obj.children [i] .style.top = top;
  49.         obj.children [i] .style.left = left;
  50.         obj.children [i] .style.width = round;
  51.         obj.children [i] .style.height = round;
  52.  
  53.         requestAnimation({
  54.             eleobj.children [i],
  55.              attr"opacity"
  56.              值:.5
  57.              timetimer
  58.              flagfalse
  59.              fnfunction() {
  60.                 requestAnimation({
  61.                     eleobj.children [i],
  62.                      attr"opacity"
  63.                      value0
  64.                      timetimer
  65.                      flagfalse
  66.                      fnfunction() {
  67.                         obj.parent.removeChildobj.children [I]);
  68.                     }
  69.                 });
  70.             }
  71.         });
  72.     }
  73.  
  74. },1000);
  75.  
  76. //月亮移动
  77. requestAnimation({
  78.     ele"#moon"
  79.      attr"right"
  80.      值:1200
  81.      时间:10000000
  82. });
  83.  
  84.  
  85. //添加云
  86. const clouds = addChild"。cloud""div"14"circle"true);
  87. forlet i = 0 ; i <clouds.children.length; i ++){
  88.      forlet j = 0 ; j <clouds.children [i] .length;){
  89.         clouds.children [i] [j] .classList.add`circle- $ {++ j} `);
  90.     }
  91. }
  92. //云动画
  93.  
  94. let flag = 1 ;
  95. setInterval
  96.     功能() {
  97.          const clouds = document .querySelectorAll"。cloud");
  98.         const left = Math .random()* 5 ;
  99.         bottom = Math .random()* 5 ;
  100.  
  101.         let timer = 0 ;
  102.         forlet i = 0 ; i <clouds.length; i ++){
  103.             requestAnimation({
  104.                 eleclouds [i],
  105.                  attr:[ "left""bottom" ],
  106.                  valueflag2?[-left,-bottom]:[leftbottom],
  107.                  timetimer + = 500
  108.                  flagfalse
  109.                  fnfunction() {
  110.                     requestAnimation({
  111.                         eleclouds [i],
  112.                          attr:[ "left""bottom" ],
  113.                          valueflag2?[leftbottom]:[ -  left,-bottom],
  114.                          timetimer
  115.                          flagfalse
  116.                     })
  117.                 }
  118.             });
  119.         }
  120.  
  121.         标志++;
  122.     },2000

封装方法

  1. // -------------------------------------------动画---- ----------------------------------------------- 
  2. //运动动画,调用Tween.js 
  3. // ele:dom | 班级| id | 标签节点| 类名| id名| 标签名,只支持选择一个节点,类类名以及标签名只能选择页面中第一个
  4. // attr:属性属性名
  5. //值:目标值目标值
  6. //时间:持续时间持续时间
  7. //补间:定时function函数方程
  8. // flag:Boolean判断是按值移动还是按位置移动,默认按位置移动
  9. // fn:callback回调函数
  10. //增加返回值:将内部参数对象返回,可以通过设置返回对象的属性stop为true打断动画
  11. 函数 requestAnimationobj {
  12.      // -------------------------------------参数设置--------------------------------------------- 
  13.     //默认属性
  14.     const参数= {
  15.          elenull
  16.          attrnull
  17.          valuenull
  18.          time1000
  19.          tween"linear"
  20.          flagtrue
  21.          stopfalse
  22.          fn""
  23.     }
  24.  
  25.     //合并传入属性
  26.     Object .assignparameterobj); //覆盖重名属性
  27.  
  28.     // -------------------------------------动画设置--------- ------------------------------------ 
  29.     //创建运动方程初始参数,方便复用
  30.     let start = 0 ; //用于保存初始时间戳
  31.     let target =(typeof parameter.ele === "string"document .querySelectorparameter.ele):parameter.ele),//目标节点 
  32.         attr = parameter.attr//目标属性 
  33.         beginAttr = parseFloatgetComputedStyletarget)[attr]),// attr起始值 
  34.         value = parameter.value//运动目标值 
  35.         count = value  -  beginAttr//实际运动值 
  36.         time = parameter.time//运动持续时间,
  37.         tween = parameter.tween//运动函数
  38.         flag = parameter.flag
  39.         callback = parameter.fn//回调函数 
  40.         curVal = 0 ; //运动当前值
  41.  
  42.     //判断传入函数是否为数组,多段运动 
  43.     function() {
  44.          ifattr instanceof  Array){
  45.             beginAttr = [];
  46.             count = [];
  47.             对于(让我的 ATTR){
  48.                  常量 VAL = parseFloat(的getComputedStyle(目标)[I]);
  49.                 beginAttr.pushVAL);
  50.                 count.pushvalue  -  val);
  51.             }
  52.         }
  53.         ifvalue instanceof  Array){
  54.              forlet i in value){
  55.                 count [i] = value [i]  -  beginAttr [i];
  56.             }
  57.         }
  58.     })();
  59.  
  60.     //运动函数
  61.     功能 动画(时间戳) {
  62.          如果(parameter.stop)返回 ; //打断
  63.         //存储初始时间戳
  64.         if(!startstart = timestamp;
  65.         //已运动时间
  66.          t =时间戳 - 开始;
  67.         //判断多段运动
  68.         ifbeginAttr instanceof  Array){
  69.              // const len = beginAttr.length //存数组长度,复用
  70.  
  71.             //多段运动第1类 - 多属性,同目标,同时间/不同时间
  72.             iftypeof count === "number"){ //同目标
  73.                 //同时间
  74.                 iftypeof time === "number"){
  75.                      ift> time= time; //判断是否超出目标值
  76.  
  77.                     //循环attr,分别赋值
  78.                     为(let i in beginAttr){
  79.                          ifflagcurVal = Tween [tween](tbeginAttr [i],counttime); //调用Tween,返回当前属性值,此时计算方法为移动到
  80.                         写入位置else curVal = Tween [tween](tbeginAttr [i],count + beginAttr [i],time); //调用Tween,返回当前属性值,此时计算方法为移动了
  81.                         写入距离ifattr [i] === "opacity"target.style [attr [i]] = curVal; //给属性赋值
  82.                         else target.style [attr [i]] = curVal + "px" ; //给属性赋值
  83.  
  84.                         if<timerequestAnimationFrameanimate); //判断是否运动完
  85.                         其他回调&& callback(); //调用回调函数
  86.                     }
  87.                     回归 ;
  88.                 }
  89.  
  90.                 //不同时间
  91.                 iftime instanceof  Array){
  92.                      //循环时间,attr,分别赋值
  93.                     为(让我在 beginAttr中){
  94.                          //错误判断
  95.                         if(!time [i] && time [i]!== 0){
  96.                              throw  new  Error
  97.                                  "输入时间的长度不等于属性的长度");
  98.                         }
  99.  
  100.                         //判断是否已经完成动画,完成则跳过此次循环
  101.                         ifparseFloatgetComputedStyletarget)[attr [i]])===(typeof value === "number"valuevalue [i]) 
  102.                              继续 ;
  103.                         // t =时间戳 - 开始; //每次循环初始化t 
  104.                         ift> time [i])= time [i]; //判断是否超出目标值
  105.  
  106.                         ifflag || attr [i] === "opacity"curVal = Tween [tween](tbeginAttr [i],counti); //调用Tween,返回当前属性值,此时计算方法为移动到
  107.                         写入位置else curVal = Tween [tween](tbeginAttr [i],count + beginAttr [i],i); //调用Tween,返回当前属性值,此时计算方法为移动了
  108.                         写入距离ifattr [i] === "opacity"target.style [attr [i]] = curVal; //给属性赋值
  109.                         else target.style [attr [i]] = curVal + "px" ; //给属性赋值
  110.                     }
  111.  
  112.                     if< Math .max(... time))requestAnimationFrameanimate); //判断函数是否运动完
  113.                     其他回调&& callback(); //如果已经执行完时间最长的动画,则调查回调函数
  114.                     return ;
  115.                 }
  116.             }
  117.  
  118.             //多段运动第2类 - 多属性,不同目标,同时间/不同时间
  119.             ifcount instanceof  Array){
  120.                  //同时间
  121.                 iftypeof time === "number"){
  122.  
  123.                     ift> time= time; //判断是否超出目标值
  124.  
  125.                     forlet i in beginAttr){ //循环attr,count,分别赋值
  126.                         //错误判断
  127.                         if(!count [i] && count [i]!== 0){
  128.                              throw  new  Error
  129.                                  "输入值的长度不是等于属性的长度");
  130.                         }
  131.  
  132.                         ifflag || attr [i] === "opacity"curVal = Tween [tween](tbeginAttr [i],count [i],time); //调用Tween,返回当前属性值,此时计算方法为移动到
  133.                         写入位置else curVal = Tween [tween](tbeginAttr [i],count [i] + beginAttr [i],time); //调用Tween,返回当前属性值,此时计算方法为移动了
  134.                         写入距离ifattr [i] === "opacity"target.style [attr [i]] = curVal; //给属性赋值
  135.                         else target.style [attr [i]] = curVal + "px" ; //给属性赋值
  136.                     }
  137.  
  138.                     if<timerequestAnimationFrameanimate); //判断函数是否运动完
  139.                     其他回调&& callback(); //如果已经执行完时间最长的动画,则调查回调函数
  140.                     return ;
  141.                 }
  142.  
  143.                 //不同时间
  144.                 iftime instanceof  Array){
  145.                      forlet i in beginAttr){
  146.                          //错误判断
  147.                         if(!time [i] && time [i]!== 0){
  148.                              throw  new  Error
  149.                                  "输入时间的长度)不等于属性的长度");
  150.                         }
  151.  
  152.                         //判断是否已经完成动画,完成则跳过此次循环
  153.                         ifparseFloatgetComputedStyletarget)[attr [i]])===(typeof value === "number"valuevalue [i]) 
  154.                              继续 ;
  155.  
  156.                         ift> time [i])= time [i]; //判断是否超出目标值
  157.  
  158.                         //错误判断
  159.                         if(!count [i] && count [i]!== 0){
  160.                              throw  new  Error
  161.                                  "输入值的长度不等于属性的长度");
  162.                         }
  163.  
  164.                         ifflag || attr [i] === "opacity"curVal = Tween [tween](tbeginAttr [i],count [i],time [i]); //调用Tween,返回当前属性值,此时计算方法为移动到
  165.                         写入位置其他 curVal = Tween [tween](tbeginAttr [i],count [i] + beginAttr [i],time [i]) ; //调用Tween,返回当前属性值,此时计算方法为移动了
  166.                         写入距离ifattr [i] === "opacity"target.style [attr [i]] = curVal;
  167.                         否则 target.style [attr [i]] = curVal + "px" ;
  168.                     }
  169.  
  170.                     if< Math .max(... time))requestAnimationFrameanimate);
  171.                     else callback && callback();
  172.                     回归 ;
  173.                 }
  174.             }
  175.  
  176.         }
  177.  
  178.         //单运动模式
  179.         ift> time= time;
  180.         ifflag || attr === "opacity"curVal = Tween [tween](tbeginAttrcounttime); //调用Tween,返回当前属性值,此时计算方法为移动到
  181.         写入位置else curVal = Tween [tween](tbeginAttr [i],count + beginAttrtime); //调用Tween,返回当前属性值,此时计算方法为移动了
  182.         写入距离ifattr === "opacity"target.style [attr] = curVal;
  183.         否则 target.style [attr] = curVal + "px" ;
  184.  
  185.         if<timerequestAnimationFrameanimate);
  186.         else callback && callback();
  187.  
  188.     }
  189.  
  190.     requestAnimationFrame(动画);
  191.     返回参数; //返回对象,供打断或其他用途
  192. }
  193. //Tween.js 
  194. / *
  195.  * t:时间已过时间
  196.  * b:开始起始值
  197.  * c:计算总的运动值
  198.  * d:持续时间持续时间
  199.  *
  200.  *曲线方程
  201.  *
  202.  * http://www.cnblogs.com/bluedream2009/archive/2010/06/19/1760909.html
  203.  * * /
  204.  
  205.  Tween = {
  206.      linearfunctiontbcd { //匀速
  207.         返回 c * t / d + b;
  208.     },
  209.     easeInfunctiontbcd { //加速曲线
  210.         return c *(/ = d)* t + b;
  211.     },
  212.     easeOutfunctiontbcd { //减速曲线
  213.         return -*(/ = d)*(t  - 2)+ b;
  214.     },
  215.     easeBothfunctiontbcd { //加速减速曲线
  216.         if((/ = d / 2)< 1){
  217.              return c / 2 * t * t + b;
  218.         }
  219.         return -/ 2 *(( -  t)*(t  - 2 - 1)+ b;
  220.     },
  221.     easeInStrongfunctiontbcd { //加加速曲线
  222.         return c *(/ = d)* t * t * t + b;
  223.     },
  224.     easeOutStrongfunctiontbcd { //减减曲线
  225.         返回 -*((= t / d  - 1)* t * t * t  - 1)+ b;
  226.     },
  227.     easeBothStrongfunctiontbcd { //加速减减速线
  228.         如果((/ = d / 2)< 1){
  229.              return c / 2 * t * t * t * t + b;
  230.         }
  231.         return -/ 2 *((t  -  = 2)* t * t * t  - 2)+ b;
  232.     },
  233.     elasticInfunctiontbcdap { //正弦衰减曲线(弹动渐入)
  234.         if=== 0){
  235.              return b;
  236.         }
  237.         if((/ = d)== 1){
  238.              return b + c;
  239.         }
  240.         if(!p){
  241.             p = d * 0.3 ;
  242.         }
  243.         if(!|| a < Math .absc)){
  244.             a = c;
  245.             var s = p / 4 ;
  246.         } else {
  247.              var s = p /(2 * Math .PI)* Math .asin/ a);
  248.         }
  249.         返回 - * 数学 .pow210 *(- = 1))* 数学 .sin((* d - S)*(2 * 数学 .PI)/ P))+ B;
  250.     },
  251.     elasticOutfunctiontbcdap { //正弦增强曲线(弹动渐出)
  252.         if=== 0){
  253.              return b;
  254.         }
  255.         if((/ = d)== 1){
  256.              return b + c;
  257.         }
  258.         if(!p){
  259.             p = d * 0.3 ;
  260.         }
  261.         if(!|| a < Math .absc)){
  262.             a = c;
  263.             var s = p / 4 ;
  264.         } else {
  265.              var s = p /(2 * Math .PI)* Math .asin/ a);
  266.         }
  267.         返回 a * Math .pow2,-10 * t)* Math .sin((* d  -  s)*(2 * Math .PI)/ p)+ c + b;
  268.     },
  269.     elasticBothfunctiontbcdap {
  270.          if=== 0){
  271.              return b;
  272.         }
  273.         if((/ = d / 2)== 2){
  274.              return b + c;
  275.         }
  276.         if(!p){
  277.             p = d *(0.3 * 1.5);
  278.         }
  279.         if(!|| a < Math .absc)){
  280.             a = c;
  281.             var s = p / 4 ;
  282.         } else {
  283.              var s = p /(2 * Math .PI)* Math .asin/ a);
  284.         }
  285.         如果(< 1){
  286.              返回 -0.5 *(* 数学 .pow210 *(- = 1))*
  287.                  数学 .sin((* d - S)*(2 * 数学 .PI)/ p))+ b;
  288.         }
  289.         返回 a * Math .pow2,-10 *(t  -  = 1))*
  290.              Math .sin((* d  -  s)*(2 * Math .PI)/ p)* 0.5 + c + b;
  291.     },
  292.     backInfunctiontbcds { //回退加速(回退渐入)
  293.         iftypeof s == 'undefined'){
  294.             s = 1.70158 ;
  295.         }
  296.         return c *(/ = d)* t *((+ 1)* t  -  s)+ b;
  297.     },
  298.     backOutfunctiontbcds {
  299.          iftypeof s == 'undefined'){
  300.             s = 3.70158 ; //回缩的距离
  301.         }
  302.         return c *((= t / d  - 1)* t *((+ 1)* t + s)+ 1)+ b;
  303.     },
  304.     backBothfunctiontbcds {
  305.          iftypeof s == 'undefined'){
  306.             s = 1.70158 ;
  307.         }
  308.         if((/ = d / 2)< 1){
  309.              return c / 2 *(* t *(((* =(1.525))+ 1)* t  -  s))+ b;
  310.         }
  311.         return c / 2 *((t  -  = 2)* t *(((* =(1.525))+ 1)* t + s)+ 2)+ b;
  312.     },
  313.     bounceInfunctiontbcd { //弹球渐出)
  314.         返回 c  -  Tween [ 'bounceOut' ](d  -  t0cd)+ b;
  315.     },
  316.     bounceOutfunctiontbcd {
  317.          if((/ = d)<(1 / 2.75)){
  318.              return c *(7.5625 * t * t)+ b;
  319.         } else  if<(2 / 2.75)){
  320.              return c *(7.5625 *(t  -  =(1.5 / 2.75))* t + 0.75)+ b;
  321.         } else  if<(2.5 / 2.75)){
  322.              return c *(7.5625 *(t  -  =(2.25 / 2.75))* t + 0.9375)+ b;
  323.         }
  324.         return c *(7.5625 *(t  -  =(2.625 / 2.75))* t + 0.984375)+ b;
  325.     },
  326.     bounceBoth:函数(TBCd {
  327.          如果(</ 2){
  328.              返回吐温[ 'bounceIn' ](* 20Cd)* 0.5 + B;
  329.         }
  330.         return Tween [ 'bounceOut' ](* 2 -  d0cd)* 0.5 + c * 0.5 + b;
  331.     }
  332. }
  333.  
  334.  
  335. // ------------------------------------------- DOM操作--- ------------------------------------------------ 
  336. //添加节点
  337. // ele:父节点,支持输入变量,id值,类值,标签值。除变量外,其余值必须为字符串
  338. //节点:添加的标签名,值为字符串
  339. // n:节点添加个数
  340. // className:节点绑定的类名,值为字符串,多个类名用空格隔开
  341. //布尔:是否选中所有目标父节点。可选参数,不输入则判定为false,则只匹配选中的第一个节点
  342. 函数 addChildelenodenclassNameboolean {
  343.      //获取节点
  344.     let parent = null ;
  345.  
  346.     iftypeof ele!== "string"parent = ele;
  347.     else  ifele [ 0 ] === "#"parent = document .getElementByIdele.slice1));
  348.     else  ifele [ 0 ] === "。"){
  349.          ifboolean === falseparent = document .getElementsByClassNameele.slice1))[ 0 ];
  350.         else parent = document .getElementsByClassNameele.slice1));
  351.     } else {
  352.          ifboolean === falseparent = docuemnt.getElementsByTagNameele)[ 0 ];
  353.         else parent = document .getElementsByTagNameNSele);
  354.     }
  355.  
  356.     //声明用于存储父节点及子节点的对象
  357.     const obj = {
  358.          "parent"parent
  359.          "children":[]
  360.     };
  361.  
  362.     //添加节点
  363.     ifboolean){
  364.          forlet i = 0 ; i <parent.length; i ++){
  365.              //创建容器碎片
  366.             const fragment = document .createDocumentFragment();
  367.             //保存子节点,用于返回值
  368.             obj.children [i] = [];
  369.  
  370.             forlet j = 0 ; j <n; j ++){
  371.                  const target = document .createElementnode);
  372.                 target.className = className;
  373.                 fragment.appendChild(目标);
  374.                 //添加子节点到数组,用于返回值
  375.                 obj.children [i] [j] =目标;
  376.             }
  377.  
  378.             父[I] .appendChild(片段)
  379.         }
  380.     } else {
  381.          //创建碎片容器
  382.         const fragment = document .createDocumentFragment();
  383.  
  384.         forlet i = 0 ; i <n; i ++){
  385.              const target = document .createElementnode);
  386.             target.className = className;
  387.             fragment.appendChild(目标);
  388.             //添加子节点,用于返回值
  389.             obj.children [i] =目标;
  390.         }
  391.         //将碎片容器一次性添加到父节点
  392.         parent.appendChild(片段);
  393.     }
  394.  
  395.     //返回参数,供动画函数调用
  396.     return obj;
  397. }

3,案例解析

HTML

由于节点很多,并且我想尽量做得逼真有趣有点,还给节点加了随机位置。所以节点的输出都是用JS控制的,HTML这边只写了几个父元素盒子,加上相应的ID名和类类名,结构相对简单。

CSS

CSS部分的难点就是流星的样式和用圈圈画云层,然后将云层堆叠出立体效果。

首先说一下流星的样式:

  1. #sky  .star {
  2.       positionabsolute;
  3.      不透明度:0 ;
  4.      z-index10000 ;
  5.  }
  6.  
  7.  .star :: after {
  8.       content"" ;
  9.      显示:块;
  10.      边界:坚固;
  11.      border-width2px  0  2px  80px ;
  12.      / *流星随长度逐渐缩小* / 
  13.      border-color:透明透明透明rgba255,255,255,1);
  14.      border-radius2px  0  0  2px ;
  15.      transformrotate(-45deg);
  16.      transform-origin0  0  0 ;
  17.      盒子阴影:0  0  20px  rgba255,255,255,.3);
  18.  }

先提取了公共样式,添加定位属性;

然后在星后通过后伪类添加流星,用边界特性画:

1)模型绘制:border-width的顺序为四边top,right,bottom,left,同理border-color的顺序也为四边top,right,bottom,left。这样将border-width与border-color一一对应后,就能看出2px的是流星的宽度,80px是流星的长度,而0像素流星就是尾巴的这样就形成了一个。头部2px的宽,尾部0像素,长度80px的流星模型 ;

2)稍微逼真:通过边界半径?给流星的头部增加个圆角,让它看起来更逼真最后通过roteta旋转一个角度,让它看起来像是往下掉;

3)增加闪光:通过箱阴影给流星增加一点光晕,让它看起来有闪光的效果;

通过以上3步,一个流星就画好了。

然后是画云:

因为云的代码比较长,这里就不贴出来了方法无非是通过一个一个的圆,相互叠加覆盖,完成一个云朵的形状。
完成一个云层之后,copy一个,然后多个云层通过rotate,opacity,left定位等,做出一个渐隐叠加的立体效果;

JS

JS部分以流星举例说明

  1. setIntervalfunction() {
  2.      const obj = addChild"#sky""div"2"star"); //插入流星
  3.  
  4.     forlet i = 0 ; i <obj.children.length; i ++){
  5.          //随机位置
  6.         const top = -50 + Math .random()* 200 + "px"
  7.             left = 200 + Math .random()* 1200 + "px"
  8.             scale = 0.3 + Math .random()* 0.5 ;
  9.         const timer = 1000 + Math .random()* 1000 ;
  10.  
  11.         obj.children [i] .style.top = top;
  12.         obj.children [i] .style.left = left;
  13.         obj.children [i] .style.transform = `scale($ {scale})` ;
  14.         
  15.         //添加动画
  16.         requestAnimation({
  17.             eleobj.children [i],
  18.              attr:[ "top""left""opacity" ],
  19.              值:[ 150,-150,.8 ],
  20.              timetimer
  21.              flagfalse
  22.              fnfunction() {
  23.                 requestAnimation({
  24.                     ELEobj.children [I],
  25.                      ATTR"顶""左""不透明" ],
  26.                      值:[ 150,-1500 ],
  27.                      时间:定时器,
  28.                      标志:假,
  29.                      FN:() => {
  30.                         obj.parent.removeChildobj.children [I]); //动画结束删除节点
  31.                     }
  32.                 })
  33.             }
  34.         });
  35.     }
  36.  
  37. },1000);

这里边用到了我自己封装的两个方法,一个是基于requestAnimationFrame的requestAnimation,以及基于appendChild的addChild。

为了达成星星位置随机的效果,通过定时器的setInterval的不停插入与删除流星:

首先,每次添加2个流星到页面,但是定时器的间隔时间小于流星的动画时间,这样就能保证页面中的流星的数量不是一个固定值,但肯定是大于2的。不然一次2个流星略显冷清;

然后,通过对循环(也可以用为式,换的,都行。对于-的最简单)给每个新添加到页面中的流星一个随机的位置(顶部,左侧),随机的大小(规模),随机的动画执行时间(定时器);

最后,在用于循环中,给每个新添加到页面中的流星加上动画,并通过回调函数在执行完动画后删除节点。这里要注意的是,要动画分成两个阶段(出现与消失,主要是opacity控制)。另外我这里的处理,每个流星都移动相同的距离300px,这个距离我觉得也可以通过随机数控制,但我犯了个懒,就没有做。

4,小问题

目前我发现的问题有2个:

一是DOM操作本身的问题页面不停的添加与删除节点,造成不停地。回流与重绘,很耗性能;

二是requestAnimationFrame本身的问题因为定时器不断在添加节点,而requestAnimationFrame的特性- 当离开当前页面去浏览其他页面时,动画会暂停。这就造成了一个问题,节点一直在加,但动画全在停那没有执行那么下次再回到这个页面的时候,就吊杆!!!动画就炸了,你会看到画面一卡,很多小蝌蚪集体出动去找妈妈。

5,结语

这个小案例虽然从难度上来看很简单,但是它可拓展性很高 - 比如表个白啊,寄个相思,耍个浪漫啊等等,用纯CSS也可以实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号