<div class="loading" id="loading">
</div>
<div class="control">
  <div class="control-form">
    <label for="dotNums">圆点个数:</label>
    <input type="number" step="1" id="dotNums" min="10" max="20" value="10" />
  </div>
  <div class="control-form">
    <label for="loadingRadius">容器半径:</label>
    <input type="range" min="50" max="200" step="1" id="loadingRadius" />
  </div>
  <div class="control-form">
    <label for="dotRadius">圆点半径:</label>
    <input type="range" min="8" max="30" step="1" id="dotRadius" />
  </div>
  <div class="control-form">
    <label for="dotColor">圆点颜色:</label>
    <input type="color" value="#d8d8d8" id="dotColor" />
  </div>
</div>
// Sass Math Function
// @function pi() {
// 	@return 3.14159265359;
// }

// @function pow($number, $exp) {
// 	$value: 1;
// 	@if $exp > 0 {
// 		@for $i from 1 through $exp {
// 			$value: $value * $number;
// 		}
// 	}
// 	@else if $exp < 0 {
// 		@for $i from 1 through -$exp {
// 			$value: $value / $number;
// 		}
// 	}
// 	@return $value;
// }

// @function fact($number) {
// 	$value: 1;
// 	@if $number > 0 {
// 		@for $i from 1 through $number {
// 			$value: $value * $i;
// 		}
// 	}
// 	@return $value;
// }

// @function rad($angle) {
// 	$unit: unit($angle);
// 	$unitless: $angle / ($angle * 0 + 1);
// 	@if $unit == deg {
// 		$unitless: $unitless / 180 * pi();
// 	}
// 	@return $unitless;
// }

// @function sin($angle) {
// 	$sin: 0;
// 	$angle: rad($angle);
// 	@for $i from 0 through 10 {
// 		$sin: $sin + pow(-1, $i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1);
// 	}
// 	@return $sin;
// }

// @function cos($angle) {
// 	$cos: 0;
// 	$angle: rad($angle);
// 	@for $i from 0 through 10 {
// 		$cos: $cos + pow(-1, $i) * pow($angle, 2 * $i) / fact(2 * $i);
// 	}
// 	@return $cos;
// }

// @function tan($angle) {
// 	@return sin($angle) / cos($angle);
// }

// >>>>>>>>>>> Let's Go!!!! >>>>>>>>>>>>>>>

body {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  
  > div {
    margin: 0 2rem;
  }
}

:root {
  --loadingRadius: 168px;
  --dotRadius: 24px;
  --dotColor: #d8d8d8;
}

.loading{
  position: relative;
  font-size: 0;
  border-radius: 50%;
  transform-origin: center;
  
  width: var(--loadingRadius);
  height: var(--loadingRadius);
  color: var(--dotColor);
  
  div {
    position: absolute;
    top: 50%;
    left: 50%;
    border-radius: 100%;

    width: var(--dotRadius);
    height: var(--dotRadius);
    color: var(--dotColor);
    margin-top: calc((var(--dotRadius) / 2) * -1);
    margin-left: calc((var(--dotRadius) / 2) * -1);
    
  }
  
  span {
    display: block;
    background-color: currentColor;
    border: 0 solid currentColor;
    border-radius: 100%;
    animation: ball-spin 1s infinite ease-in-out;  
    
    width: var(--dotRadius);
    height: var(--dotRadius);
  }
}

// animation keyframes

@keyframes ball-spin {
    0%,
    100% {
      opacity: 1;
      transform: scale(1);
    }
    20% {
      opacity: 1;
    }
    80% {
      opacity: 0;
      transform: scale(0);
    }
}

.control-form {
  margin: 10px 0;
}
View Compiled
const style = document.documentElement.style;
var rangs = {
  dotNums: document.getElementById('dotNums'),
  loadingRadiusVal: document.getElementById('loadingRadius'),
  dotRadiusVal: document.getElementById('dotRadius'),
  dotColorVal: document.getElementById('dotColor')
}

function valueChange(id, value) {
  style.setProperty('--' + id, value);
}

function insertHtml() {
  let loadingWrap = document.getElementById('loading');
  var dots = rangs.dotNums.value;
  
  for(let i = 0; i < dots; i++) {
    let divEle = document.createElement('div');
    let spanEle = document.createElement('span');
    divEle.appendChild(spanEle);
    loadingWrap.appendChild(divEle)
  }  
}

rangs.loadingRadiusVal.addEventListener('input', function(e){
  valueChange(e.currentTarget.id, e.currentTarget.value + 'px');
})
rangs.dotRadiusVal.addEventListener('input', function(e){
  valueChange(e.currentTarget.id, e.currentTarget.value + 'px');
})
rangs.dotColorVal.addEventListener('input', function(e){
  valueChange(e.currentTarget.id, e.currentTarget.value);
})

function transformDot() {
  let dotNums = document.querySelectorAll('.loading > div');
  let loadingRadiusVal = rangs.loadingRadiusVal.value;
  let dotRadiusVal = rangs.dotRadiusVal.value;
  let dotColorVal = rangs.dotColorVal.value;
  console.log(`loadingRadiusValue: ${loadingRadiusVal}, dotRadiusVal: ${dotRadiusVal},dotColorVal: ${dotColorVal}`);
  for (let i = 0, len = dotNums.length; i < len; i++) {
    // rad = (2 * Math.PI / 360) * 360 / dotNums.length  * i;
    let rad = 2 * Math.PI / dotNums.length  * i;
    let dotX =  Math.cos(rad) * loadingRadiusVal / 2;
    let dotY =  Math.sin(rad) * loadingRadiusVal / 2;
    dotNums[i].style.transform = `translate(${dotX}px,${dotY}px)`;
    dotNums[i].firstElementChild.style.animationDelay = -1 * (1 + (i + 1) * 1 / dotNums.length) + 's';
    console.log(dotNums[i].style.transform);
    console.log(dotNums[i].firstElementChild.style.animationDelay);
  }
}

insertHtml();
transformDot();

rangs.dotNums.addEventListener('input', function(e){
  let loadingWrap = document.getElementById('loading');
  loadingWrap.innerHTML = '';
  insertHtml();
  transformDot();
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.