这是一款基于JS和SVG的超酷下雨特效。该特效通过在js代码构建SVG线条,并使线条运动起来,形成下雨效果,非常炫酷。
使用方法
JS代码
function rain(el = document.body, params) { if (!el) { console.error('Must have element to populate the rain!'); return; } const defaultProperties = { colors: 'default', drop: window.innerHeight, fadeout: true, raindrops: 400, speed: 2000, splashes: true, spread: window.innerWidth }; // properties passed in from user onto the defaults const c = Object.assign(defaultProperties, params); const randInt = (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; }; let hh = window.innerHeight; let ww = window.innerWidth; let raindrops = ''; let rainsplashes = ''; if (!c.flakes || Number.isNaN(c.flakes * 1)) { c.flakes = 250; } for (let i = 0; i < c.flakes; i++) { if (window.CP.shouldStopExecution(0)) break; let dur = c.speed; raindrops += `<g transform="translate(${randInt(0, ww)} -26) scale(1.${randInt(0, 3)})"> <rect id="snowflake${i}" fill="rgba(240, 240, 255, ${randInt(1, 10) / 10})" x="0" y="0" rx="1" height="${randInt(4, 10)}" width="${randInt(3, 5) / 10}" filter="url(#blur${randInt(1, 2)})"> </rect> </g> <animateMotion xlink:href="#snowflake${i}" dur="${dur}ms" begin="-${randInt(0, 100) / 10}s" repeatCount="indefinite"> <mpath xlink:href="#motionPath${randInt(1, 2)}" /> </animateMotion>`; // animated circle splashes if (c.splashes) { if (randInt(0, 1) == 1) { let randTiming = -randInt(0, 10) / 10; rainsplashes += `<ellipse stroke="rgba(240, 240, 255, ${randInt(1, 4) / 10})" stroke-width="1" fill="none" cx="${randInt(0, ww)}" cy="${randInt(hh, hh / 1.2)}" rx="5" ry="3"> <animate attributeType="XML" attributeName="stroke-width" dur="1s" values="0; 0.7; 0" repeatCount="indefinite" begin="${randTiming}" /> <animate attributeType="XML" attributeName="rx" dur="${c.speed / 2}ms" values="0; ${randInt(5, 9)}" repeatCount="indefinite" additive="sum" begin="${randTiming}" /> <animate attributeType="XML" attributeName="ry" dur="${c.speed / 2}ms" values="0; ${randInt(1, 2)}" repeatCount="indefinite" additive="sum" begin="${randTiming}" /> <!-- <animate attributeType="XML" attributeName="cx" dur="${c.speed / 2}ms" values="${randInt(0, ww)}; ${randInt(0, ww)}" repeatCount="indefinite" additive="sum" begin="${randTiming}" /> --> </ellipse>`; } } } window.CP.exitedLoop(0); let svg = `<svg id="snowverlay" viewbox="0 0 ${ww} ${hh}" height="${hh}" width="${ww}" preserveAspectRatio="none" style="z-index:99999; user-select:none; pointer-events:none; top:50%; left:50%; position:fixed; transform:translate(-50%,-50%)"> <filter id="blur1" x="-100%" y="-100%" width="300%" height="300%"> <feGaussianBlur in="SourceGraphic" stdDeviation="1" /> </filter> <filter id="blur2" x="-100%" y="-100%" width="300%" height="300%"> <feGaussianBlur in="SourceGraphic" stdDeviation="2" /> </filter> <path id="motionPath1" fill="none" stroke="none" d="M 0 -${hh * 0.1} V ${hh * 1.1}" /> <path id="motionPath2" fill="none" stroke="none" d="M 0 -${hh * 0.1} V ${hh * 1.1}" /> ${raindrops} ${rainsplashes} </svg>`; //Make it a node to avoid the dangerous "document.body.innerHTML = svg" let wrapper = document.createElement("div"); wrapper.innerHTML = svg; let doc = wrapper.firstChild; const element = document.getElementById("snowverlay"); element?.remove(); document.body.appendChild(doc); } window.onload = rain(document.body); window.onresize = rain;