Requirements describe

Before showing the page with the actual content, use an HTML page for the transition effect:

  • The progress bar increases from 0% to 99% unevenly
  • Once the actual content is ready, the progress bar is set to 100%
  • Remove current page

Train of thought

For faster loading and rendering, we write the logic in native javaScript and draw the UI with the native Progress tag

This paper will focus on the realization of “non-uniform increasing”, which can be divided into the following two points:

  • Achieve high frequency numerical changes
  • Incrementing values nonlinearly

1. High frequency numerical changes

We can use requestAnimationFrame to keep the frequency of progress bar updates consistent with the frequency of screen refreshes

The frameId variable is used to hold the identifier, making it easier to cancel the callback function at a specific time

let frameId; Function autoIncrement() {frameId = requestAnimationFrame(autoIncrement)} autoIncrement();Copy the code

2. Incrementing values nonlinearly

We can maintain two variables currentValue and nextValue, representing the currentValue and the value of the next frame respectively

Each time the autoIncrement function is executed, assign nextValue to currentValue plus a random number of [0,1]

To keep the page clean, only the integer part of the value is displayed, and the code is implemented as follows:

let currentValue, nextValue; const progressNumber = document.getElementById('progress-number'); const progressBar = document.getElementById('progress-bar'); function setProgress(currentValue, nextValue) { if (! progressNumber || ! progressBar) { cancelAnimationFrame(frameId); return; } const invalidValue = currentValue < 0 || currentValue > 99 || nextValue > 99; if (invalidValue) { cancelAnimationFrame(frameId); return; } progressNumber.innerText = nextValue.toFixed(0); progressBar.setAttribute('value', nextValue.toFixed(0)); } function autoIncrement() { currentValue = parseInt(progressNumber.innerText); nextValue = currentValue + Math.random(); setProgress(currentValue, nextValue); frameId = requestAnimationFrame(autoIncrement); }Copy the code

Finally, we want to set the progress bar to 100% and remove the current page once the actual content is ready

function completeProgress() { if (! progressNumber || ! progressBar) { cancelAnimationFrame(frameId); return; } progressNumber.innerText = '100'; progressBar.setAttribute('value', '100'); } function onRemoveLoading() { cancelAnimationFrame(frameId); completeProgress(); SetTimeout (() => {// remove DOM node}, 100); } window.addEventListener('removeLoading', onRemoveLoading);Copy the code

In the page component that has the actual content, choose to dispatch events at the right time

const removeLoadingEvent = new CustomEvent('removeLoading');
dispatchEvent(removeLoadingEvent);
Copy the code

UI

<style> #progress-bar { width: 202px; height: 10px; margin: 20px 0 10px; overflow: hidden; vertical-align: unset; background: #cce6ff; -webkit-appearance: none; border-radius: 12px; } #progress-bar::-webkit-progress-bar {background-color: # FFF; background-color: # FFF; } #progress-bar::-webkit-progress-value {background-image: linear-gradient(90deg, #755AF7 0%, #1650D5 100%); border-radius: 12px; } </style> <div id="loading-fake"> <div class="init-loading-wrapper"> <img class="init-loading-img" /> <progress Id ="progress-bar" Max ="100" value="0" ></progress> <div class="progress-number-wrapper"> <div> - </div> <div> <span Id = "progress - the number" > 0 < / span > < span > % < / span > < / div > < div > - < / div > < / div > < / div > < / div >Copy the code