Heim  >  Artikel  >  Web-Frontend  >  Wie kann man mit CSS+JS einen romantischen Meteorschauer-Animationseffekt erzielen? (Codebeispiel)

Wie kann man mit CSS+JS einen romantischen Meteorschauer-Animationseffekt erzielen? (Codebeispiel)

青灯夜游
青灯夜游nach vorne
2018-11-10 17:16:582876Durchsuche

Der Inhalt dieses Artikels besteht darin, vorzustellen, wie man den romantischen Meteorschauer-Animationseffekt mit CSS + JS realisiert. (Codebeispiel). Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird Ihnen hilfreich sein.

Schauen wir uns zunächst die Renderings an:

Wie kann man mit CSS+JS einen romantischen Meteorschauer-Animationseffekt erzielen? (Codebeispiel)

Los geht's it next Sehen Sie, wie es funktioniert:

HTML-Code:

 
     
          p > 
          p > 
          p > 
          p > 
         p > 
        <p>  p > 
          p > 
     p > 
 body ></p>

CSS-Code:

/*  -  -  -  -  -  - 重启 -  -  -  -  -  -  */
 
 * {
     保证金:0 ;
     填充:0 ;
 }
 
 html,
  body {
      width:100% ;
     最小宽度:1000px ;
     身高:100% ;
     最小高度:400px ;
     溢出:隐藏;
 }

 / * ------------画布------------ * / 
 .container {
      position:relative;
     身高:100% ;
 }
 / *遮罩层* /
 
 #mask {
      position:absolute;
     宽度:100% ;
     身高:100% ;
     background:rgba(0,0,0,.8);
     z-index:900 ;
 }
 / *天空背景* /
 
 #sky {
      width:100% ;
     身高:100% ;
     background:线性渐变(rgba(0,150,255,1),rgba(0,150,255,.8),rgba(0,150,255,.5));
 }
 / *月亮* /
 
 #moon {
      position:absolute;
     上:50px ;
     右:200px ;
     宽度:120px ;
     身高:120px ;
     背景: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);
     不透明度:0 ;
     z-index:10000 ;
 }
 / *流星* /
 
 .star {
      position:absolute;
     不透明度:0 ;
     z-index:10000 ;
 }
 
 .star :: after {
      content:“” ;
     显示:块;
     边界:坚固;
     border-width:2px  0  2px  80px ;
     / *流星随长度逐渐缩小* / 
     border-color:透明透明透明rgba(255,255,255,1);
     border-radius:2px  0  0  2px ;
     transform:rotate(-45deg);
     transform-origin:0  0  0 ;
     盒子阴影:0  0  20px  rgba(255,255,255,.3);
 }
 / *云* /
 
 .cloud {
      position:absolute;
     宽度:100% ;
     身高:100px ;
 }
 
 .cloud-1 {
      bottom: - 100px ;
     z-index:1000 ;
     不透明度:1 ;
     变换:规模(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 ;
     底部: - 50px ;
     z-index:999 ;
     不透明度:。5 ;
     变换:旋转(7deg);
     -webkit-transform:rotate(7deg);
     -moz-transform:rotate(7deg);
     -ms-transform:rotate(7deg);
     -o-transform:rotate(7deg);
 }
 
 .cloud-3 {
      left:120px ;
     底部: - 50px ;
     z-index:999 ;
     不透明度:。1 ;
     transform:rotate(-10deg);
     -webkit-transform:rotate(-10deg);
     -moz-transform:rotate(-10deg);
     -ms-transform:rotate(-10deg);
     -o-transform:rotate(-10deg);
 }
 
 .circle {
      position:absolute;
     border-radius:50% ;
     背景:#fff ;
 }
 
 .circle-1 {
      width:100px ;
     身高:100px ;
     上: - 50px ;
     左:10px ;
 }
 
 .circle-2 {
      width:150px ;
     身高:150px ;
     上: - 50px ;
     左:30px ;
 }
 
 .circle-3 {
      width:300px ;
     身高:300px ;
     上: - 100px ;
     左:80px ;
 }
 
 .circle-4 {
      width:200px ;
     身高:200px ;
     上: - 60px ;
     左:300px ;
 }
 
 .circle-5 {
      width:80px ;
     身高:80px ;
     上: - 30px ;
     左:450px ;
 }
 
 .circle-6 {
      width:200px ;
     身高:200px ;
     上: - 50px ;
     左:500px ;
 }
 
 .circle-7 {
      width:100px ;
     身高:100px ;
     上: - 10px ;
     左:650px ;
 }
 
 .circle-8 {
      width:50px ;
     身高:50px ;
     上:30px ;
     左:730px ;
 }
 
 .circle-9 {
      width:100px ;
     身高:100px ;
     上:30px ;
     左:750px ;
 }
 
 .circle-10 {
      width:150px ;
     身高:150px ;
     上:10px ;
     左:800px ;
 }
 
 .circle-11 {
      width:150px ;
     身高:150px ;
     上: - 30px ;
     左:850px ;
 }
 
 .circle-12 {
      width:250px ;
     身高:250px ;
     上: - 50px ;
     左:900px ;
 }
 
 .circle-13 {
      width:200px ;
     身高:200px ;
     上: - 40px ;
     左:1000px ;
 }
 
 .circle-14 {
      width:300px ;
     身高:300px ;
     上: - 70px ;
     左:1100px ;
 }

JS-Code:

//流星动画 
setInterval(function() {
     const obj = addChild(“#sky”,“p”,2,“star”);

    for(let i = 0 ; i <obj.children.length> {
                        obj.parent.removeChild(obj.children [I]);
                    }
                })
            }
        });
    }

},1000);

//闪烁星星动画 
setInterval(function() {
     const obj = addChild(“#stars”,“p”,2,“blink”);

    for(let i = 0 ; i <obj.children.length requestanimation const for let><p><strong>Kapselungsmethode: </strong></p>
<pre class="brush:php;toolbar:false">// -------------------------------------------动画---- ----------------------------------------------- 
//运动动画,调用Tween.js 
// ele:dom | 班级| id | 标签节点| 类名| id名| 标签名,只支持选择一个节点,类类名以及标签名只能选择页面中第一个
// attr:属性属性名
//值:目标值目标值
//时间:持续时间持续时间
//补间:定时function函数方程
// flag:Boolean判断是按值移动还是按位置移动,默认按位置移动
// fn:callback回调函数
//增加返回值:将内部参数对象返回,可以通过设置返回对象的属性stop为true打断动画
函数 requestAnimation(obj) {
     // -------------------------------------参数设置--------------------------------------------- 
    //默认属性
    const参数= {
         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 = [];
            对于(让我的 ATTR){
                 常量 VAL = parseFloat(的getComputedStyle(目标)[I]);
                beginAttr.push(VAL);
                count.push(value  -  val);
            }
        }
        if(value instanceof  Array){
             for(let i in value){
                count [i] = value [i]  -  beginAttr [i];
            }
        }
    })();

    //运动函数
    功能 动画(时间戳) {
         如果(parameter.stop)返回 ; //打断
        //存储初始时间戳
        if(!start)start = timestamp;
        //已运动时间
        让 t =时间戳 - 开始;
        //判断多段运动
        if(beginAttr instanceof  Array){
             // const len = beginAttr.length //存数组长度,复用

            //多段运动第1类 - 多属性,同目标,同时间/不同时间
            if(typeof count === “number”){ //同目标
                //同时间
                if(typeof time === “number”){
                     if(t> time)t = time; //判断是否超出目标值

                    //循环attr,分别赋值
                    为(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> time [i])t = time [i]; //判断是否超出目标值

                        if(flag || attr [i] === “opacity”)curVal = Tween [tween](t,beginAttr [i],count,i); //调用Tween,返回当前属性值,此时计算方法为移动到
                        写入位置else curVal = Tween [tween](t,beginAttr [i],count + beginAttr [i],i); //调用Tween,返回当前属性值,此时计算方法为移动了
                        写入距离if(attr [i] === “opacity”)target.style [attr [i]] = curVal; //给属性赋值
                        else target.style [attr [i]] = curVal + “px” ; //给属性赋值
                    }

                    if(t  time)t = time; //判断是否超出目标值

                    for(let i in beginAttr){ //循环attr,count,分别赋值
                        //错误判断
                        if(!count [i] && count [i]!== 0){
                             throw  new  Error(
                                 “输入值的长度不是等于属性的长度“);
                        }

                        if(flag || attr [i] === “opacity”)curVal = Tween [tween](t,beginAttr [i],count [i],time); //调用Tween,返回当前属性值,此时计算方法为移动到
                        写入位置else curVal = Tween [tween](t,beginAttr [i],count [i] + beginAttr [i],time); //调用Tween,返回当前属性值,此时计算方法为移动了
                        写入距离if(attr [i] === “opacity”)target.style [attr [i]] = curVal; //给属性赋值
                        else target.style [attr [i]] = curVal + “px” ; //给属性赋值
                    }

                    if(t <time> time [i])t = time [i]; //判断是否超出目标值

                        //错误判断
                        if(!count [i] && count [i]!== 0){
                             throw  new  Error(
                                 “输入值的长度不等于属性的长度”);
                        }

                        if(flag || attr [i] === “opacity”)curVal = Tween [tween](t,beginAttr [i],count [i],time [i]); //调用Tween,返回当前属性值,此时计算方法为移动到
                        写入位置其他 curVal = Tween [tween](t,beginAttr [i],count [i] + beginAttr [i],time [i]) ; //调用Tween,返回当前属性值,此时计算方法为移动了
                        写入距离if(attr [i] === “opacity”)target.style [attr [i]] = curVal;
                        否则 target.style [attr [i]] = curVal + “px” ;
                    }

                    if(t  time)t = time;
        if(flag || attr === “opacity”)curVal = Tween [tween](t,beginAttr,count,time); //调用Tween,返回当前属性值,此时计算方法为移动到
        写入位置else curVal = Tween [tween](t,beginAttr [i],count + beginAttr,time); //调用Tween,返回当前属性值,此时计算方法为移动了
        写入距离if(attr === “opacity”)target.style [attr] = curVal;
        否则 target.style [attr] = curVal + “px” ;

        if(t <time><p><span style="font-size: 20px;"><strong>Fallanalyse</strong></span></p> <p><strong>HTML</strong></p>
<p>Da es viele Knoten gibt und ich es so realistisch und interessant wie möglich machen wollte, habe ich den Knoten auch zufällige Positionen hinzugefügt. Daher wird die Ausgabe von Knoten von JS gesteuert. Auf der HTML-Seite werden nur wenige übergeordnete Elementfelder sowie die entsprechenden ID-Namen und Klassennamen geschrieben, und die Struktur ist relativ einfach. </p>
<p><strong>CSS</strong></p>
<p>Der schwierige Teil des CSS-Teils ist der Stil des Meteors und das Zeichnen der Wolken mit Kreisen und das anschließende Stapeln der Wolken, um ein dreidimensionales Bild zu erzeugen Wirkung. </p>
<p>Lassen Sie uns zunächst über den Stil des Meteors sprechen: </p>
<pre class="brush:php;toolbar:false">#sky  .star {
      position:absolute;
     不透明度:0 ;
     z-index:10000 ;
 }
 
 .star :: after {
      content:“” ;
     显示:块;
     边界:坚固;
     border-width:2px  0  2px  80px ;
     / *流星随长度逐渐缩小* / 
     border-color:透明透明透明rgba(255,255,255,1);
     border-radius:2px  0  0  2px ;
     transform:rotate(-45deg);
     transform-origin:0  0  0 ;
     盒子阴影:0  0  20px  rgba(255,255,255,.3);
 }

extrahierte zuerst den öffentlichen Stil und fügte das Positionierungsattribut hinzu

und fügte dann den Meteor über die Pseudoklasse hinzu der Stern, unter Verwendung des Randattributs Zeichnung:

1) Modellzeichnung: Die Reihenfolge der Randbreite ist oben, rechts, unten, links. Ebenso ist die Reihenfolge der Randfarbe oben, rechts, unten, unten. links. Auf diese Weise können Sie nach einer Eins-zu-eins-Entsprechung zwischen Randbreite und Randfarbe sehen, dass 2 Pixel die Breite des Meteors, 80 Pixel die Länge des Meteors und der 0-Pixel-Meteor der Schweif ist. so entsteht ein. Meteormodell mit Kopf 2 Pixel breit, Schwanz 0 Pixel und Länge 80 Pixel;

2) Etwas realistisch: nach Grenzradius? Fügen Sie dem Kopf des Meteors eine abgerundete Ecke hinzu, damit er realistischer aussieht. Drehen Sie ihn schließlich in einem Winkel, damit er aussieht, als würde er fallen.

3) Fügen Sie Glanz hinzu: Fügen Sie einen Kastenschatten hinzu Fügen Sie dem Meteor einen kleinen Heiligenschein hinzu, damit er funkelnd aussieht;

Nach den oben genannten 3 Schritten ist eine Sternschnuppe fertig.

Dann zeichnen Sie Wolken:

Da der Wolkencode relativ lang ist, werde ich ihn hier nicht veröffentlichen. Die Methode besteht lediglich darin, Kreise einzeln zu überlappen und abzudecken, um die Form zu vervollständigen eine Wolke.
Nachdem Sie eine Wolkenebene fertiggestellt haben, kopieren Sie eine und verwenden Sie dann mehrere Wolkenebenen, um einen dreidimensionalen Effekt aus Verblassen und Überlappen zu erzeugen.

JS

Der JS-Teil verwendet Meteor als Beispiel

setInterval(function() {
     const obj = addChild(“#sky”,“p”,2,“star”); //插入流星

    for(let i = 0 ; i <obj.children.length> {
                        obj.parent.removeChild(obj.children [I]); //动画结束删除节点
                    }
                })
            }
        });
    }

},1000);</obj.children.length>

Ich verwende hier zwei von mir selbst gekapselte Methoden, eine ist requestAnimation basierend auf requestAnimationFrame und addChild basierend auf appendChild.

Um den Effekt zufälliger Sternpositionen zu erzielen, werden Meteore kontinuierlich über das eingestellte Intervall des Timers eingefügt und gelöscht:

Fügen Sie zunächst jedes Mal 2 Meteore zur Seite hinzu, aber das Intervall des Timers kleiner als die Animationszeit des Meteors, dadurch wird sichergestellt, dass die Anzahl der Meteore auf der Seite kein fester Wert ist, sondern größer als 2 sein muss. Andernfalls sind 2 Meteore gleichzeitig etwas verlassen.

Geben Sie dann jedem neu hinzugefügten Meteor auf der Seite eine zufällige Position (oben, links), eine zufällige Größe (Skalierung) und eine zufällige Animationsausführungszeit (Timer). );

Schließlich fügen Sie in der Schleife jedem neu zur Seite hinzugefügten Meteor eine Animation hinzu und löschen den Knoten, nachdem die Animation über die Rückruffunktion ausgeführt wurde. Hierbei ist zu beachten, dass die Animation in zwei Phasen unterteilt ist (Erscheinen und Verschwinden, hauptsächlich Steuerung der Deckkraft). Außerdem bewegt sich bei meiner Verarbeitung hier jeder Meteor um die gleiche Distanz von 300 Pixeln. Ich denke, diese Distanz kann auch durch Zufallszahlen gesteuert werden, aber ich war faul und habe es nicht getan.

Kleine Probleme

Derzeit habe ich zwei Probleme gefunden:

Erstens besteht das Problem mit der DOM-Operation selbst darin Die Seite fügt nicht ständig Knoten hinzu und löscht sie, was zu Ununterbrochenem führt. Reflow und Neuzeichnen sind sehr leistungsintensiv;

Das zweite Problem ist requestAnimationFrame selbst, da der Timer ständig Knoten hinzufügt, und die Eigenschaften von requestAnimationFrame – wenn die aktuelle Seite verlassen wird, um andere Seiten zu durchsuchen, wird die Animation angehalten . Dadurch entsteht ein Problem, aber die Animation stoppt und wird nicht ausgeführt. Wenn Sie dann das nächste Mal auf diese Seite zurückkehren, explodiert die Animation und Sie werden sehen, dass der Bildschirm einfriert Gemeinsam machen sie sich auf die Suche nach ihrer Mutter.

Fazit

Obwohl dieser kleine Fall vom Schwierigkeitsgrad her sehr einfach ist, ist er zum Beispiel sehr skalierbar, um meine Liebe auszudrücken. Liebe senden, romantisch sein usw. kann auch mit reinem CSS erreicht werden.

Das obige ist der detaillierte Inhalt vonWie kann man mit CSS+JS einen romantischen Meteorschauer-Animationseffekt erzielen? (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen