js实现夜晚月亮下云层上流星雨动画效果代码

代码语言:html

所属分类:动画

代码描述:js实现夜晚月亮下云层上流星雨动画效果代码

代码标签: 夜色 月亮 云层 流星雨 动画

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">






    <style>
        /* ------------reset------------ */
         
         * {
             margin: 0;
             padding: 0;
         }
         
         html,
         body {
             width: 100%;
             min-width: 1000px;
             height: 100%;
             min-height: 400px;
             overflow: hidden;
         }
         .container {
             position: relative;
             width: 100%;
             height: 100%;
             min-width: 100px;
             min-height: 400px;
         }
         /*  ------------画布 ------------ */
         /* 遮罩层 */
         
         #mask {
             position: absolute;
             width: 100%;
             height: 100%;
             background: rgba(0, 0, 0, .8);
             z-index: 900;
         }
         /* 天空背景 */
         
         #sky {
             width: 100%;
             height: 100%;
             background: linear-gradient(rgba(0, 150, 255, 1), rgba(0, 150, 255, .8), rgba(0, 150, 255, .5));
         }
         /* 月亮 */
         
         #moon {
             position: absolute;
             top: 50px;
             right: 200px;
             width: 120px;
             height: 120px;
             background: rgba(251, 255, 25, 0.938);
             border-radius: 50%;
             box-shadow: 0 0 20px rgba(251, 255, 25, 0.5);
             z-index: 9999;
         }
         /* 闪烁星星 */
         
         .blink {
             position: absolute;
             background: rgb(255, 255, 255);
             border-radius: 50%;
             box-shadow: 0 0 5px rgb(255, 255, 255);
             opacity: 0;
             z-index: 10000;
             animation: blingbling 2s linear infinite;
         }
         /* 流星 */
         
         .star {
             position: absolute;
             opacity: 0;
             animation: fall 5s linear infinite;
             z-index: 10000;
         }
         
         .star::after {
             content: "";
             display: block;
             border: solid;
             border-width: 2px 0 2px 80px;
             /*流星随长度逐渐缩小*/
             border-color: transparent transparent transparent rgba(255, 255, 255, 1);
             border-radius: 2px 0 0 2px;
             transform: rotate(-45deg);
             transform-origin: 0 0 0;
             box-shadow: 0 0 20px rgba(255, 255, 255, .3);
         }
         /* 云 */
         
         .cloud {
             position: absolute;
             width: 100%;
             height: 100px;
             /* background: #fff; */
             animation: float 2s linear infinite;
         }
         
         .cloud-1 {
             bottom: -100px;
             z-index: 1000;
             opacity: 1;
             animation-delay: 1s;
             transform: scale(1.5);
             -webkit-transform: scale(1.5);
             -moz-transform: scale(1.5);
             -ms-transform: scale(1.5);
             -o-transform: scale(1.5);
         }
         
         .cloud-2 {
             left: -100px;
             bottom: -50px;
             z-index: 999;
             opacity: .5;
             transform: rotate(7deg);
             animation-delay: 1.4s;
         }
         
         .cloud-3 {
             left: 120px;
             bottom: -50px;
             z-index: 999;
             opacity: .1;
             transform: rotate(-10deg);
             animation-delay: 1.8s;
         }
         
         .circle {
             position: absolute;
             border-radius: 50%;
             background: #fff;
         }
         
         .circle-1 {
             width: 100px;
             height: 100px;
             top: -50px;
             left: 10px;
         }
         
         .circle-2 {
             width: 150px;
             height: 150px;
             top: -50px;
             left: 30px;
         }
         
         .circle-3 {
             width: 300px;
             height: 300px;
             top: -100px;
             left: 80px;
         }
         
         .circle-4 {
             width: 200px;
             height: 200px;
             top: -60px;
             left: 300px;
         }
         
         .circle-5 {
             width: 80px;
             height: 80px;
             top: -30px;
             left: 450px;
         }
         
         .circle-6 {
             width: 200px;
             height: 200px;
             top: -50px;
             left: 500px;
         }
         
         .circle-7 {
             width: 100px;
             height: 100px;
             top: -10px;
             left: 650px;
         }
         
         .circle-8 {
             width: 50px;
             height: 50px;
             top: 30px;
             left: 730px;
         }
         
         .circle-9 {
             width: 100px;
             height: 100px;
             top: 30px;
             left: 750px;
         }
         
         .circle-10 {
             width: 150px;
             height: 150px;
             top: 10px;
             left: 800px;
         }
         
         .circle-11 {
             width: 150px;
             height: 150px;
             top: -30px;
             left: 850px;
         }
         
         .circle-12 {
             width: 250px;
             height: 250px;
             top: -50px;
             left: 900px;
         }
         
         .circle-13 {
             width: 200px;
             height: 200px;
             top: -40px;
             left: 1000px;
         }
         
         .circle-14 {
             width: 300px;
             height: 300px;
             top: -70px;
             left: 1100px;
         }
         /*动画*/
         /*云*/
         /*@keyframes float {
               0% {
                   bottom: -50px;
               }
               50% {
                   bottom: -45px;
               }
               100% {
                   bottom: -50px;
               }
           }*/
    </style>


</head>

<body>
    <!-- 
    相比于纯CSS写法,动画的效果更华丽,可以一直在随机位置变更节点,动画看起来更具有“活性”。但同时对于性能的消耗也更高
    另外,由于动画函数采用requestAnimationFrame封装,然后通过setInterval不停添加节点并调用动画
    如果跳转至其他页面,在此期间定时器会不停添加节点,而动画则一直处于暂停状态
    再次返回页面时,动画效果会聚集,然后一瞬间释放出来,可能浏览器会崩溃
 -->


    <div class="container">
        <div id="mask"></div>
        <div id="sky"></div>
        <div id="moon"></div>
        <div id="stars"></div>
        <div class="cloud cloud-1"></div>
        <div class="cloud cloud-2"></div>
        <div class="cloud cloud-3"></div>
     
    </div>



<script>
    //流星动画
        setInterval(function () {
          const obj = addChild("#sky", "div", 2, "star");
        
          for (let i = 0; i < obj.children.length; i++) {
            const top = -50 + Math.random() * 200 + "px",
            left = 200 + Math.random() * 1200 + "px",
            scale = 0.3 + Math.random() * 0.5;
            const timer = 1000 + Math.random() * 1000;
        
            obj.children[i].style.top = top;
            obj.children[i].style.left = left;
            obj.children[i].style.transform = `scale(${scale})`;
        
            requestAnimation({
              ele: obj.children[i],
              attr: ["top", "left", "opacity"],
              value: [150, -150, .8],
              time: timer,
              flag: false,
              fn: function () {
                requestAnimation({
                  ele: obj.children[i],
                  attr: ["top", "left", "opacity"],
                  value: [150, -150, 0],
                  time: timer,
                  flag: false,
                  fn: () => {
                    obj.parent.removeChild(obj.children[i]);
                  } });
        
              } });
        
          }
        
        }, 1000);
        
        //闪烁星星动画
        setInterval(function () {
          const obj = addChild("#stars", "div", 2, "blink");
        
          for (let i = 0; i < obj.children.length; i++) {
            const top = -50 + Math.random() * 500 + "px",
            left = 200 + Math.random() * 1200 + "px",
            round = 1 + Math.random() * 2 + "px";
            const timer = 1000 + Math.random() * 4000;
        
            obj.children[i].style.top = top;
            obj.children[i].style.left = left;
            obj.children[i].style.width = round;
            obj.children[i].style.height = round;
        
            requestAnimation({
              ele: obj.children[i],
              attr: "opacity",
              value: .5,
              time: timer,
              flag: false,
              fn: function () {
                requestAnimation({
                  ele: obj.children[i],
                  attr: "opacity",
                  value: 0,
                  time: timer,
                  flag: false,
                  fn: function () {
                    obj.parent.removeChild(obj.children[i]);
                  } });
        
              } });
        
          }
        
        }, 1000);
        
        //月亮移动
        requestAnimation({
          ele: "#moon",
          attr: "right",
          value: 1200,
          time: 10000000 });
        
        
        
        // 添加云
        const clouds = addChild(".cloud", "div", 14, "circle", true);
        for (let i = 0; i < clouds.children.length; i++) {
          for (let j = 0; j < clouds.children[i].length;) {
            clouds.children[i][j].classList.add(`circle-${++j}`);
          }
        }
        //云动画
        
        let flag = 1;
        setInterval(
        function () {
          const clouds = document.querySelectorAll(".cloud");
          const left = Math.random() * 5;
          bottom = Math.random() * 5;
        
          let timer = 0;
          for (let i = 0; i < clouds.length; i++) {
            requestAnimation({
              ele: clouds[i],
              attr: ["left", "bottom"],
              value: flag % 2 ? [-left, -bottom] : [left, bottom],
              time: timer += 500,
              flag: false,
              fn: function () {
                requestAnimation({
                  ele: clouds[i],
                  attr: ["left", "bottom"],
                  value: flag % 2 ? [left, bottom] : [-left, -bottom],
                  time: timer,
                  flag: false });
        
              } });
        
          }
        
          flag++;
        }, 2000);
        
        //———————————————————————————————————————————动画———————————————————————————————————————————————————
        //运动动画,调用Tween.js
        //ele: dom | class | id | tag  节点 | 类名 | id名 | 标签名,只支持选择一个节点,class类名以及标签名只能选择页面中第一个
        //attr: attribute 属性名
        //value: target value 目标值
        //time: duration 持续时间
        //tween: timing function 函数方程
        //flag: Boolean 判断是按值移动还是按位置移动,默认按位置移动
        //fn: callback 回调函数
        //增加返回值: 将内部参数对象返回,可以通过设置返回对象的属性stop为true打断动画
        function requestAnimation(obj) {
          //—————————————————————————————————————参数设置—————————————————————————————————————————————
          //默认属性
          const parameter = {
            ele: null,
            attr: null,
            value: null,
            time: 1000,
            tween: "linear",
            flag: true,
            stop: false,
            fn: "" };
        
        
          //合并传入属性
          Object.assign(parameter, obj); //覆盖重名属性
        
          //—————————————————————————————————————动画设置—————————————————————————————————————————————
          //创建运动方程初始参数,方便复用
          let start = 0; //用于保存初始时间戳
          let target = typeof parameter.ele === "string" ? document.querySelector(parameter.ele) : parameter.ele, //目标节点
          attr = parameter.attr, //目标属性
          beginAttr = parseFloat(getComputedStyle(target)[attr]), //attr起始值
          value = parameter.value, //运动目标值
          count = value - beginAttr, //实际运动值
          time = parameter.time, //运动持续时间,
          tween = parameter.tween, //运动函数
          flag = parameter.flag,
          callback = parameter.fn, //回调函数
          curVal = 0; //运动当前值
        
          //判断传入函数是否为数组,多段运动
          (function () {
            if (attr instanceof Array) {
              beginAttr = [];
              count = [];
              for (let i of attr) {
                const val = parseFloat(getComputedStyle(target)[i]);
                beginAttr.push(val);
                count.push(value - val);
              }
            }
            if (value instanceof Array) {
              for (let i in value) {
                count[i] = value[i] - beginAttr[i];
              }
            }
          })();
        
          //运动函数
          function animate(timestamp) {
            if (parameter.stop) return; //打断
            //存储初始时间戳
            if (!start) start = timestamp;
            //已运动时间
            let t = timestamp - start;
            //判断多段运动
            if (beginAttr instanceof Array) {
              // const len = beginAttr.length //存数组长度,复用
        
              //多段运动第1类——多属性,同目标,同时间/不同时间
              if (typeof count === "number") {//同目标
                //同时间
                if (typeof time === "number") {
                  if (t > time) t = time; //判断是否超出目标值
        
                  //循环attr,分别赋值
                  for (let i in beginAttr) {
                    if (flag) curVal = Tween[tween](t, beginAttr[i], count, time); //调用Tween,返回当前属性值,此时计算方法为移动到写入位置
                    else curVal = Tween[tween](t, beginAttr[i], count + beginAttr[i], time); //调用Tween,返回当前属性值,此时计算方法为移动了写入距离
                    if (attr[i] === "opacity") target.style[attr[i]] = curVal; //给属性赋值
                    else target.style[attr[i]] = curVal + "px"; //给属性赋值
        
                    if (t < time) requestAnimationFrame(animate); //判断是否运动完
                    else callback && callback(); //调用回调函数
                  }
                  return;
                }
        
                //不同时间
                if (time instanceof Array) {
                  //循环time,attr,分别赋值
                  for (let i in beginAttr) {
                    //错误判断
                    if (!time[i] && time[i] !== 0) {
              .........完整代码请登录后点击上方下载按钮下载查看

网友评论0