前言

有需求写一个大转盘的功能

网上搜了一些,一部分没有实现样式,直接用了一个大转盘的UI图片

还有一些是写死了样式

感觉不是很灵活,所以打算自己写一个

今天先实现样式,主要是奖项的旋转角度和扇形的实现,能根据奖项数量自动计算样式,效果如图

html+css+js实现大转盘-1_自定义数量

html+css+js实现大转盘-1_自定义数量_02

思路

有一个外部容器,里面放着若干奖项元素

奖项元素宽度为100%,高度为外部容器的一半,position为absolute,left、top都为0

奖项元素的旋转角度为360度除以奖项数量旋转基点底部中间位置

奖项元素扇形,使用clip-pathpath来切割形状为倒三角形,然后外部容器overflowhidden,这样就能遮挡倒三角的外围

代码实现

html

<div class="wheel">
    <div class="prize">Prize 1</div>
    <div class="prize">Prize 2</div>
    <div class="prize">Prize 3</div>
    <div class="prize">Prize 4</div>
    <div class="prize">Prize 5</div>
    <div class="prize">Prize 6</div>
    <div class="prize">Prize 7</div>
    <div class="prize">Prize 8</div>
  </div>

上面为外部容器奖项元素,不做过多介绍

CSS样式

.wheel {
    width: 400px;
    height: 400px;
    position: relative;
    background-color: #f39c12;
    border-radius: 50%;
    overflow: hidden;
  }
  
  .prize {
    width: 100%;
    height: 50%;
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    box-sizing: border-box;
    transform-origin: center bottom;
  }
  
  .prize:nth-child(1) { background-color: #3498db; }
  .prize:nth-child(2) { background-color: #e74c3c; }
  .prize:nth-child(3) { background-color: #2ecc71; }
  .prize:nth-child(4) { background-color: #e67e22; }
  .prize:nth-child(5) { background-color: #9b59b6; }
  .prize:nth-child(6) { background-color: #f1c40f; }
  .prize:nth-child(7) { background-color: #1abc9c; }
  .prize:nth-child(8) { background-color: #34495e; }

设置外部容器的基本样式,比如尺寸位置以及溢出隐藏

设置奖项元素的尺寸,位置弹性盒子旋转基点

JS代码

js代码的主要有2个功能:

计算每个奖项元素的旋转角度

这个比较简单啦,上面也说了360/奖项数量

/**
 * @description: 得出奖项旋转角度
 * @return {*}
 */
function getRotate(){
  // 获取奖项列表
  let items = document.querySelectorAll('.prize');
  // 得出每个奖项的旋转角度
  return jiaodu = 360 / items.length;
}

计算扇形的clip-path的path路径

这个需要用到三角函数求边长的知识,作为初中文化水平的我,也是费了点劲儿才搞定,哈哈

html+css+js实现大转盘-1_随机_03

比如一共有5个奖项元素,那么每个奖项元素占据的角度就是72°,青色的角度就是36°,直到矩形高度为200宽度为400,需要求得的值,知道的值,就能得出path的三个顶点位置,通过三角函数的tan能得出X的值,的值就是宽度/2 - X

需要注意的是js中角度需要换算为弧度在再进行使用

弧度 = 角度 * Math.PI / 180

下面直接上代码,多了我也说不清

设直角三角形中C=90°

1、若已知A及对边a,则:c=a/sinA,     b=a/tanA;

2、若已知A及临边b,则:c=b/cosA,    a=b*tanA.

我也是根据上面的公式算出来

/**
 * @description: 根据已知条件计算出clip-path的切割路径
 * @param {*} height 矩形的高
 * @param {*} width 矩形的宽
 * @return {*}
 */
function getPath(height, width){
  // 获取奖项列表
  let items = document.querySelectorAll('.prize');
  // 得出每个奖项的角度,然后除以2得出夹角度数
  let jiaodu = 360 / items.length / 2;
  // 得出短直角边的长度
  let duan = (width/2) - Math.tan(jiaodu/180*Math.PI)*height;
  // let duan = Math.sin(jiaodu*Math.PI/180)*height;
  // 拼接路径信息
  let path = `M ${duan} 0 L ${width-duan} 0 L ${width/2} ${height}`;
  return path;
}

根据SVG中的path的解释

html+css+js实现大转盘-1_自定义数量_04

说一下16行这个路径的含义,只看Prize 1 ,就是1,2,3的顺序切割了一块

html+css+js实现大转盘-1_盘_05

然后样式自动根据奖项数量变化就完成了

总结

主要用到了三角函数clip-pathpathtransformrotate

明天再写一下转盘转动以及停到中奖位置的功能吧