This is the second day of my participation in Gwen Challenge

preface

Recently, the epidemic broke out in Guangzhou, and it always rained! But let a person be touched, many, many people, day and night, braving the rain to go to the front line, rain or shine to protect us!

I want to give the website a baptism of rain by myself, remember these lovely people, and hope the epidemic passes away as soon as possible

Analyze requirements

Rain for the whole page, a rain is composed of countless raindrops, so we can use div or canvas to achieve raindrops, in addition, we need a special raindrop constructor, and each drop of rain its position, size, falling speed and direction are different

It rains

Use div to simulate raindrops

body .rain {
    display: block;
    width: 2px;
    height: 50px;
    background-image: radial-gradient(#fff 0%.rgba(255.255.255.0) 60%);
    margin: 0 auto;
}
Copy the code

Display a drop of rain as shown

But we need a lot of raindrops, so we can’t write that

Use JS to dynamically generate N drops of rain

1. You need a constructor first

The constructor generates raindrops, but note that the location, speed, and direction of each drop may be different

class Rain {
    constructor(opt = {}) {
        // Each EL is a raindrop
        this.el = null;
        // The location of raindrops
        this.x = 0;
        this.y = 0;
        // The granularity of rain
        this.width = opt.width;
        this.maxWidth = opt.maxWidth || 3;
        this.minWidth = opt.minWidth || 1;
        // The length of raindrops
        this.height = 0;
        this.maxHeight = opt.maxHeight || 30;
        this.minHeight = opt.minHeight || 20;
        // The falling speed of the rain
        this.speed_x = 0
        this.speed_y = 0
        this.maxSpeed = opt.maxSpeed || 100;
        this.minSpeed = opt.minSpeed || 10;
        // Initialize the data
        this.init(); }}Copy the code

So, as you can see, when you create an object with new Rain, you’re going to have properties that we’ve preset, like the size of the raindrop width and height, the x and y falling rates speed_x and speed_y and so on and you’re going to need an init function to initialize the object

2. Initialize basic object information

init() {
    // Initializes the random raindrop size within the specified range
    this.width = Math.floor(Math.random() * this.maxWidth + this.minWidth)
    this.height = Math.floor(Math.random() * this.maxHeight + this.minHeight)
    // Initialize random raindrop locations in the specified range
    this.x = Math.floor(Math.random() * (window.innerWidth - this.width))
    this.y = Math.floor(Math.random() * (window.innerHeight - this.height))
    // Initializes the random raindrop speed within the specified range
    this.speed_y = Math.random() * this.maxSpeed + this.minSpeed
    this.speed_x = Math.random() * this.maxSpeed 
}
Copy the code

As shown in the code above, the initial raindrop includes three sets of values width and height, X-axis and Y-axis positions, and the speed of rain speed_y and speed_x. The reason for setting the two speeds is to make the horizontal and vertical speed of rain different. Note that you can control the amount of rain here, so you can adjust the rain here later

After initializing the raindrop information, the raindrop style needs to be added

3. Add a set style function

setStyle() {
    this.el.style.cssText = `
        position:fixed;
        left:0;
        top:0;
        display:block;
        width:The ${this.width}px;
        height:The ${this.height}px;
        background-image: radial-gradient(#fff 0%, rgba(255, 255, 255, 0) 60%);
        z-index: 999999999;
        opacity:.6;
        pointer-events: none;
        transform: translate(The ${this.x}px, The ${this.y}px);
    `
}
Copy the code

Once you’ve set the basic style of the raindrop with the setStyle function, you then need a function that creates a real element to render the raindrop

4. Render raindrops

render() {
    this.el = document.createElement('div')
    this.setStyle()
    document.body.appendChild(this.el)
}
Copy the code

Create the Render function, assign the el of the object to the newly created div DOM element, set the style with setStyle, and add it to the page with appendChild

5. Try making 1000 raindrops

let rainList = []
for (let i = 0; i <= 1000; i++) {
    let rain = new Rain();
    rain.render();
    rainList.push(rain);
}
Copy the code

Create the number of raindrops we want with the for loop and render it to the page. Store the raindrops with rainList.

The result of creating raindrops is as follows

But the rain could not move. Somehow it had to be made to move

6. Let it rain

Create a move method that changes the position of the raindrop, but needs to be careful to determine the boundary. When the boundary is beyond, reinitialize it to run to other visible areas, and reset the random style so that continuous drops fall

move() {
    // this.x += this.speed_x
    this.y += this.speed_y
    // Determine the boundary
    if (this.x < -this.width || this.x > window.innerWidth || this.y > window.innerHeight) {
        this.init()
        this.setStyle()
    }
    this.el.style.transform = `translate(The ${this.x}px, The ${this.y}px)`

}
Copy the code

The above code calls only move once at a time, so use a timer to keep it moving. Or use Windows requestAnimationFrame, this method is used to before the page re-paint, notify the browser call a specified function. RequestAnimationFrame has two main advantages over setTimeout and setInterval:

  1. requestAnimationFrameIt’s going to take all of the framesDOMThe operations are centralized and done in a single redraw or reflow, and the redraw or reflow interval closely tracks the browser’s refresh rate, which is typically every second60The frame;
  2. In hidden or invisible elements,requestAnimationFrameThere will be no repainting or reflow, which of course means lesscpuAnd memory usage;
function moveRain() {
    window.requestAnimationFrame(() = > {
        rainList.forEach((item) = > {
            item.move()
        })
        moveRain()
    })
}
Copy the code

Finally, execute moveRain

moveRain()
Copy the code

7. Effect display

The result is shown in figure

As you can see, the general result is already in. The rain pattern and the size and speed can be adjusted by yourself. There will be different rain patterns: bigger rain, for example

let rain = new Rain({
    maxWidth:5.speemaxSpeed:150
});

Copy the code

The results are as follows

In addition, it is impossible to only float down in the afternoon every time, and sometimes it is windy. This can be adjusted by adjusting the horizontal offset position as follows:

    move() {
        this.x += 5; . }Copy the code

The result is shown in figure

summary

This example reviews the basic use of native apis. But there are still many problems and some areas to be improved. Such as:

  1. Code reusability; Can it be used on individual elements that you want to reference?
  2. So manydivPerformance issues with movement
  3. There is always less rain at the top, but the main reason is when you first go out of sight;
  4. Is there any other way we can do this? Such ascanvas, performance will be better

And so on…

Remark:

  1. Inspiration: juejin.cn/post/691085…
  2. The above code has been uploaded to github: github.com/jCodeLife/r…
  3. Novice white, unavoidably have run off. There are incorrect, hope the criticism pointed out, I will correct in time, thank you!!