今天產品須要 要求把原來的活動功能改爲大轉盤形式的 因而乎我也是第一次作這種需求 就動手擼了一個javascript
需求分析css
css3
的transform
transition
的各類屬性clip
裁剪由於最近在搭react 18.9+webpack4.x+less等等各類的架構(也還在加深學習hook) 因此順手就用react寫的 若是有須要 其實我也有vue版 差不太多的vue
上代碼 (基本樣式 這裏是用的less寫的)java
.project {
overflow: hidden;
&-content {
padding-top: 5rem;
position: relative;
img {
width: 60px;
height: 60px;
transform: translateY(-8px) translateX(-30px);
position: absolute;
left: 50%;
top: 50%;
z-index: 10
}
&-box {
position: relative;
background: url('~@/assets/draw_bg.png') no-repeat;
background-size: 100% 100%;
width: 300px;
height: 300px;
margin: auto;
transition: all 5s ease;
&-item {
position: absolute;
font-size: 16px;
height: 150px;
width: 40px;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
margin: auto;
right: 0;
transform-origin: 20px 150px;
&.li0 {
transform: rotate(22.5deg)
}
&.li1 {
transform: rotate(67.5deg)
}
&.li2 {
transform: rotate(112.5deg)
}
&.li3 {
transform: rotate(157.5deg)
}
&.li4 {
transform: rotate(202.5deg)
}
&.li5 {
transform: rotate(247.5deg)
}
&.li6 {
transform: rotate(292.5deg)
}
&.li7 {
transform: rotate(337.5deg)
}
}
}
}
}
複製代碼
transition
我本身選用的是ease
的動畫方式開始慢中間快結束慢 有須要也能夠手寫速度react
對應的每個刻度的角度 下面的註釋裏有講 應該很好理解webpack
主要用到了transform-origin
進行的平移rotate
旋轉 這邊就不講細節了css3
下面就是核心代碼web
import React, { useEffect, useRef, useState } from 'react'
import './style.less'
import { Modal } from 'antd';
export default () => {
const [timer, setTimer] = useState(null)
const box = useRef(null)
useEffect(() => {
// 清除計時 我有強迫症 請忽略
return () => clearTimeout(timer)
}, [timer])
const handle = () => {
// 起始圈數
const speed = 7
// 拿到服務端返回的獎項索引
const index = 4
// 這裏的45度 由於這裏是按八塊一圈 360 / 8 - 45 * 刻度 加上22.5是由於對應的刻度要加上45每格的一半(順時針如此)
const _deg = speed * 360 - index * 45 + 22.5
// 開始動畫
box.current.style.transition = 'all 5s ease'
box.current.style.transform = `rotate(${_deg}deg)`
// 方式屢次重複點擊
if (timer) { return }
setTimer(setTimeout(() => {
Modal.success({
title: '領取獎勵',
content: '確認',
onOk: () => new Promise((resolve, reject) => {
// 清空動畫
Object.assign(box.current.style, {
transform: '',
transition: 'none'
})
resolve()
})
})
// 清除計時器修改時間爲null方便上面驗證
clearTimeout(timer)
setTimer(null)
}, 5000))
}
return (
<div className='project'> <div className="project-content"> <img onClick={handle} src={require('@/assets/draw_btn.png')} alt=""/> <div ref={box} className="project-content-box"> { [...Array(8).keys()].map((n) => { return ( <div key={n} className={'project-content-box-item '+`li${n}`}>{n}</div> ) }) } </div> </div> </div> ) } 複製代碼
這裏是用的ref
操做的dom
節點樣式 antd
的確認彈框組件作的確認回調antd
至於清空樣式的時機 能夠本身拓展 固然也能夠不清空 在原有基礎上開始轉 那樣deg
的數值就是在原有的基礎上加了(由於若是直接覆蓋的話 動畫效果會在原有基礎上去轉動 會有問題) 具體算的話須要計算原來所在的刻度 而後加上所缺而後補齊到0而後再進行刻度和圈數的增長架構
爲了節約時間 點擊觸發沒有作詳細防抖 作了一個簡易的驗證 是那個意思
speed index
對應獎項這些能夠對應業務需求去拓展 我這邊就很少說了
其實真的本身動手作起來發現其實並無什麼難點 記錄來玩玩
若是真的有人須要vue
的版本的話 能夠評論我發給你 我就不帖在這了