擼一個簡易大轉盤

今天產品須要 要求把原來的活動功能改爲大轉盤形式的 因而乎我也是第一次作這種需求 就動手擼了一個javascript

需求分析css

  • 第一想法既然是轉盤 原地轉那固然想到了css3transform
  • 動畫實現了 那轉盤上對應的刻度對應展現如何實現呢? 我想到的是平移 各類x,y,z軸。但用的畢竟仍是不是很是多 因而我又去複習了一下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的版本的話 能夠評論我發給你 我就不帖在這了

相關文章
相關標籤/搜索