欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何使用React構(gòu)建一個(gè)擲骰子的小游戲

 更新時(shí)間:2024年12月23日 14:36:02   作者:練習(xí)兩年半的工程師  
這篇文章主要介紹了如何使用React構(gòu)建一個(gè)擲骰子的小游戲,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧

這是一個(gè)用 React 構(gòu)建的小游戲應(yīng)用,名為 Tenzies,目標(biāo)是擲骰子,直到所有骰子的值相同。玩家可以“凍結(jié)”某些骰子,使它們?cè)诤罄m(xù)擲骰中保持不變。

1. App.jsx

import Die from "../public/components/Die"
import { useState, useRef, useEffect } from "react"
import { nanoid } from "nanoid"
import Confetti from "react-confetti"
  • Die:自定義組件,用于顯示單個(gè)骰子。
  • useState、useRef、useEffect:React hooks,用于管理狀態(tài)、DOM引用和副作用。
  • nanoid:用于生成唯一 ID 的庫(kù),確保每個(gè)骰子有唯一標(biāo)識(shí)符。
  • Confetti:庫(kù)組件,用于顯示游戲勝利的彩帶特效。

初始化狀態(tài)和引用

export default function App(){
  const [dice, setDice] = useState(() => generateAllNewDice())
  const buttonRef = useRef(null)

dice:管理 10 個(gè)骰子的數(shù)組狀態(tài)。初始值通過 generateAllNewDice 函數(shù)生成。
buttonRef:引用按鈕 DOM 元素,用于在勝利時(shí)自動(dòng)聚焦。

游戲勝利條件

const gameWon = dice.every(die => die.isHeld) && 
  dice.every(die => die.value === dice[0].value)

游戲勝利的條件:

  • 所有骰子的 isHeld 屬性為 true(即凍結(jié))。
  • 所有骰子的值相同。

處理副作用

useEffect(() => {
  if (gameWon) {
    buttonRef.current.focus()
  }
}, [gameWon])

當(dāng) gameWontrue 時(shí),自動(dòng)讓“新游戲”按鈕獲得焦點(diǎn),提升可用性。

生成新的骰子數(shù)組

function generateAllNewDice() {
  return new Array(10).fill(0).map(() => ({
    value: Math.ceil(Math.random() * 6),
    isHeld: false,
    id: nanoid()
  }))
}

創(chuàng)建 10 個(gè)骰子對(duì)象,每個(gè)骰子有:

  • value:1 到 6 的隨機(jī)數(shù)。
  • isHeld:初始為 false,表示未凍結(jié)。
  • id:唯一標(biāo)識(shí)符,使用 nanoid 生成。

Math.ceil(Math.random() * 6) 是 JavaScript 中生成隨機(jī)整數(shù)的常見方法之一。下面逐步解釋其工作原理:

Math.random()

  • 作用:生成一個(gè) 0(包含)到 1(不包含) 的隨機(jī)浮點(diǎn)數(shù)。
  • 范圍[0, 1)。

例如:可能的結(jié)果是 0.2345, 0.9876, 0.0012 等。

Math.random() * 6

  • 作用:將生成的隨機(jī)數(shù)放大至 0 到 6(不包含 6) 的范圍。
  • 范圍[0, 6)。

示例: 如果 Math.random() 返回 0.2,則 0.2 * 6 = 1.2。

如果 Math.random() 返回 0.9,則 0.9 * 6 = 5.4。

Math.ceil()

作用:對(duì)數(shù)字向上取整,返回大于等于該數(shù)的最小整數(shù)。

  • 例如: Math.ceil(1.2) 返回 2
  • Math.ceil(5.4) 返回 6。
  • Math.ceil(0) 返回 0。

綜合步驟

Math.ceil(Math.random() * 6) 的完整過程:

  • 調(diào)用 Math.random() 生成一個(gè)隨機(jī)數(shù),例如 0.45
  • 將該隨機(jī)數(shù)乘以 6,結(jié)果是 2.7
  • Math.ceil() 對(duì)結(jié)果向上取整,得到 3。

返回結(jié)果

最終的返回值是一個(gè) 1 到 6 的隨機(jī)整數(shù)

  • 范圍[1, 6]。
  • 為何能覆蓋 1 到 6?
    • Math.random() 取值為 0 時(shí),Math.random() * 6 = 0,取整后為 1。
    • Math.random() 接近 1 時(shí),Math.random() * 6 接近 6,取整后為 6

擲骰子邏輯

function rollDice() {
  if (!gameWon) {
    setDice(oldDice => oldDice.map(die => 
      die.isHeld ?
        die :
        {...die, value: Math.ceil(Math.random() * 6)}
    ))
  } else {
    setDice(generateAllNewDice())
  }
}

游戲未勝利時(shí):

對(duì)未凍結(jié)的骰子重新生成隨機(jī)值。

游戲勝利時(shí):

重置游戲,生成新的骰子數(shù)組。

切換凍結(jié)狀態(tài)

function hold(id) {
  setDice(oldDice => oldDice.map(die =>
    die.id === id ?
      {...die, isHeld: !die.isHeld} :
      die
  ))
}

根據(jù)點(diǎn)擊的骰子 id,切換對(duì)應(yīng)骰子的 isHeld 狀態(tài)。

顯示骰子

const diceElements = dice.map(dieObj => 
  (<Die 
    key={dieObj.id} 
    value={dieObj.value} 
    isHeld={dieObj.isHeld}
    hold={() => hold(dieObj.id)}
  />)
)
  • 使用 map 遍歷 dice 狀態(tài),為每個(gè)骰子生成一個(gè) Die 組件。
  • hold 函數(shù)傳遞給每個(gè)骰子,用于處理點(diǎn)擊事件。

渲染 UI

return (
  <main>
    {gameWon && <Confetti />}
    <div aria-live="polite" className="sr-only">
        {gameWon && <p>Congratulations! You won! Press "New Game" to start again.</p>}
    </div>
    <h1 className="title">Tenzies</h1>
    <p className="instructions">Roll until all dice are the same. Click each die to freeze it at its current value between rolls.</p>
    <div className="dice-container">
      {diceElements}
    </div>
    <button ref={buttonRef} className="roll-dice" onClick={rollDice}>
      {gameWon ? "New Game" : "Roll"}
    </button>
  </main>
)
  • 勝利時(shí)顯示彩帶效果:通過 Confetti 組件。
  • 無障礙支持:aria-live 提供游戲狀態(tài)描述。
  • 骰子容器:動(dòng)態(tài)顯示所有 Die 組件。
  • 按鈕文本:勝利時(shí)為“New Game”,否則為“Roll”。

代碼的核心邏輯總結(jié)

  • 初始狀態(tài)下生成 10 個(gè)隨機(jī)骰子。
  • 用戶點(diǎn)擊骰子時(shí),可凍結(jié)當(dāng)前骰子值。
  • 點(diǎn)擊按鈕:
    – 若游戲未勝利,則重新擲未凍結(jié)的骰子。
    – 若游戲勝利,則重置游戲。
  • 實(shí)現(xiàn)游戲勝利條件檢測(cè)和 UI 提示(如彩帶效果、自動(dòng)聚焦按鈕)。

2. Die.jsx

export default function Die(props) {
    const styles = {
        backgroundColor: props.isHeld ? "#59E391" : "white"
    }

styles 是一個(gè)動(dòng)態(tài)樣式對(duì)象,用于控制按鈕的背景顏色:

  • 如果 props.isHeld 為 true(表示該骰子被凍結(jié)),背景顏色為綠色 (#59E391)。
  • 如果 props.isHeld 為 false(表示未凍結(jié)),背景顏色為白色。

樣式切換使用戶能夠直觀地看到凍結(jié)狀態(tài)。

return (
    <button 
        style={styles}
        onClick={props.hold}
        aria-pressed={props.isHeld}
        aria-label={`Die with value ${props.value}, 
        ${props.isHeld ? "held" : "not held"}`}
    >
        {props.value}
    </button>
)

style={styles}

  • 將動(dòng)態(tài)樣式對(duì)象 styles 應(yīng)用到按鈕的 style 屬性,調(diào)整按鈕的背景顏色。

onClick={props.hold}

  • 定義按鈕的點(diǎn)擊事件處理函數(shù)。
  • props.hold 是從父組件傳遞的函數(shù),當(dāng)用戶點(diǎn)擊按鈕時(shí)會(huì)觸發(fā)這個(gè)函數(shù)。
  • 通常,props.hold 用于切換 isHeld 狀態(tài),凍結(jié)或解凍當(dāng)前骰子。

aria-pressed={props.isHeld}

  • 用于無障礙支持。
  • 指定按鈕的按下狀態(tài):true:表示當(dāng)前骰子已被“按下”或凍結(jié)。
  • false:表示當(dāng)前骰子未被按下。幫助屏幕閱讀器用戶了解當(dāng)前狀態(tài)。

aria-label={Die with value ${props.value}, ${props.isHeld ? “held” : “not held”}}

  • 用于描述按鈕的詳細(xì)信息,提升無障礙性。
  • 動(dòng)態(tài)生成描述,例如:Die with value 4, held:骰子的值為 4,已凍結(jié)。Die with value 6, not held:骰子的值為 6,未凍結(jié)。
  • 代碼的核心功能 動(dòng)態(tài)顯示骰子的值。
  • 提供交互功能,點(diǎn)擊按鈕會(huì)調(diào)用 props.hold,切換凍結(jié)狀態(tài)。通過動(dòng)態(tài)樣式反映骰子的狀態(tài)(凍結(jié)或未凍結(jié))。提供無障礙支持,便于屏幕閱讀器識(shí)別和描述按鈕狀態(tài)。

3. index.css

1. 通用選擇器 *

* {
  box-sizing: border-box;
}
  • 作用:將所有元素的 box-sizing 設(shè)置為 border-box。
  • box-sizing: border-box;
    • 包括內(nèi)容、內(nèi)邊距 (padding) 和邊框 (border) 的寬度和高度在 widthheight 的計(jì)算中。
    • 效果:簡(jiǎn)化布局調(diào)整,避免意外的尺寸增大。

2. body 樣式

body {
  font-family: Karla, sans-serif;
  margin: 0;
  background-color: #0B2434;
  padding: 20px;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
  • 字體font-family: Karla, sans-serif; 使用 Karla 字體,不支持時(shí)回退到無襯線字體。
  • 背景顏色:深藍(lán)色背景 (#0B2434)。
  • 布局
    • display: flex;:將 body 設(shè)為彈性容器。
    • flex-direction: column;:子元素垂直排列。
    • justify-content: center;:子元素在垂直方向上居中。
    • align-items: center;:子元素在水平方向上居中。
  • 高度100vh 使 body 占據(jù)整個(gè)視口高度。
  • 內(nèi)邊距20px,用于給內(nèi)容留出額外空間。

3. div#root 樣式

div#root {
  height: 100%;
  width: 100%;
  max-height: 400px;
  max-width: 400px;
}
  • 高度和寬度:默認(rèn)占據(jù)父容器的全部空間。
  • 最大尺寸限制max-heightmax-width 分別限制為 400px。
    • 效果:即使父容器較大,#root 的尺寸也不會(huì)超過 400 像素。

4. main 樣式

main {
  background-color: #F5F5F5;
  height: 100%;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: center;
}
  • 背景顏色:淺灰色 (#F5F5F5)。
  • 圓角border-radius: 5px; 使容器的邊角圓滑。
  • 布局: 彈性布局,子元素垂直排列。
    • justify-content: space-evenly;:在主軸上均勻分布子元素,間隔相等。
    • align-items: center;:子元素在交叉軸(水平方向)上居中。

5. .title 樣式

.title {
  font-size: 40px;
  margin: 0;
}

字體大小40px。

邊距margin: 0; 去除外邊距。

6. .instructions 樣式

.instructions {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  margin-top: 0;
  text-align: center;
}

字體:優(yōu)先使用 Inter 字體。

字體粗細(xì):普通粗細(xì) (font-weight: 400)。

文本對(duì)齊:居中對(duì)齊 (text-align: center)。

7. .dice-container 樣式

.dice-container {
  display: grid;
  grid-template: auto auto / repeat(5, 1fr);
  gap: 20px;
  margin-bottom: 40px;
}
  • 布局:CSS 網(wǎng)格布局。
    • grid-template
      • 行模板:auto auto(兩行,每行高度自適應(yīng)內(nèi)容)。
      • 列模板:repeat(5, 1fr)(5 列,每列寬度相等)。
    • gap: 20px;:網(wǎng)格單元之間的間距。
  • 底部邊距:margin-bottom: 40px;。

8. 通用按鈕樣式

button {
  font-family: Karla, sans-serif;
  cursor: pointer;
}
  • 字體Karla
  • 鼠標(biāo)樣式cursor: pointer; 鼠標(biāo)懸停時(shí)顯示手型圖標(biāo)。

9. .dice-container button 樣式

.dice-container button {
  height: 50px;
  width: 50px;
  box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.15);
  border-radius: 10px;
  border: none;
  background-color: white;
  font-size: 1.75rem;
  font-weight: bold;
}
  • 按鈕尺寸:固定寬高 50px。
  • 陰影box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.15); 添加輕微的陰影效果。
  • 圓角border-radius: 10px;。
  • 無邊框border: none;
  • 背景顏色:白色。
  • 字體樣式
    • font-size: 1.75rem; 大號(hào)字體。
    • font-weight: bold; 加粗。

10. .roll-dice 按鈕樣式

button.roll-dice {
  height: 50px;
  white-space: nowrap;
  width: auto;
  padding: 6px 21px;
  border: none;
  border-radius: 6px;
  background-color: #5035FF;
  color: white;
  font-size: 1.2rem;
}
  • 尺寸:高度固定為 50px,寬度根據(jù)內(nèi)容調(diào)整。
  • 背景顏色:深藍(lán)色 (#5035FF)。
  • 字體顏色:白色。
  • 內(nèi)邊距6px(垂直)和 21px(水平)。無邊框,并帶有圓角。

11. .sr-only 樣式

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
  • 作用:隱藏元素,但保留給屏幕閱讀器使用。
  • 關(guān)鍵屬性
    • position: absolute;:從文檔流中移除。
    • widthheight 設(shè)置為 1px。
    • 使用 clipoverflow 確保內(nèi)容不可見。
    • 提供無障礙支持,例如為視覺障礙用戶提供額外的語(yǔ)音描述。

總結(jié)

這段 CSS 代碼:

  • 設(shè)計(jì)布局:通過彈性盒布局和網(wǎng)格布局組織內(nèi)容。
  • 樣式統(tǒng)一性:使用動(dòng)態(tài)樣式、字體和交互效果。
  • 無障礙支持:添加屏幕閱讀器友好的隱藏元素(.sr-only)。
  • 視覺細(xì)節(jié):通過顏色、圓角、陰影和間距提升用戶體驗(yàn)。

到此這篇關(guān)于使用React構(gòu)建一個(gè)擲骰子的小游戲的文章就介紹到這了,更多相關(guān)React擲骰子的小游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React中的生命周期詳解

    React中的生命周期詳解

    這篇文章主要介紹了React中的生命周期,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-09-09
  • React?中hooks之?React.memo?和?useMemo用法示例總結(jié)

    React?中hooks之?React.memo?和?useMemo用法示例總結(jié)

    React.memo是一個(gè)高階組件,用于優(yōu)化函數(shù)組件的性能,通過記憶組件渲染結(jié)果來避免不必要的重新渲染,合理使用React.memo和useMemo可以顯著提升React應(yīng)用的性能,本文介紹React?中hooks之?React.memo?和?useMemo用法總結(jié),感興趣的朋友一起看看吧
    2025-01-01
  • react中如何使用監(jiān)聽

    react中如何使用監(jiān)聽

    在 React 中,您可以使用?addEventListener?函數(shù)來監(jiān)聽事件,本文通過實(shí)例代碼給大家介紹react中如何使用監(jiān)聽,感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • react hooks實(shí)現(xiàn)原理解析

    react hooks實(shí)現(xiàn)原理解析

    這篇文章主要介紹了react hooks實(shí)現(xiàn)原理,文中給大家介紹了useState dispatch 函數(shù)如何與其使用的 Function Component 進(jìn)行綁定,節(jié)后實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • 你知道怎么基于?React?封裝一個(gè)組件嗎

    你知道怎么基于?React?封裝一個(gè)組件嗎

    這篇文章主要為大家詳細(xì)介紹了React如何封裝一個(gè)組件,使用antd的divider組件來講解,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • React hooks如何清除定時(shí)器并驗(yàn)證效果

    React hooks如何清除定時(shí)器并驗(yàn)證效果

    在React中,通過自定義Hook useTimeHook實(shí)現(xiàn)定時(shí)器的啟動(dòng)與清除,在App組件中使用Clock組件展示當(dāng)前時(shí)間,利用useEffect鉤子在組件掛載時(shí)啟動(dòng)定時(shí)器,同時(shí)確保組件卸載時(shí)清除定時(shí)器,避免內(nèi)存泄露,這種方式簡(jiǎn)化了狀態(tài)管理和副作用的處理
    2024-10-10
  • React構(gòu)建簡(jiǎn)潔強(qiáng)大可擴(kuò)展的前端項(xiàng)目架構(gòu)

    React構(gòu)建簡(jiǎn)潔強(qiáng)大可擴(kuò)展的前端項(xiàng)目架構(gòu)

    這篇文章主要為大家介紹了React構(gòu)建簡(jiǎn)潔強(qiáng)大可擴(kuò)展的前端項(xiàng)目架構(gòu)實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • React項(xiàng)目如何使用Element的方法步驟

    React項(xiàng)目如何使用Element的方法步驟

    本文主要介紹了React項(xiàng)目如何使用Element的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • react swiper@6.x 工作中遇到的問題處理方案

    react swiper@6.x 工作中遇到的問題處理方案

    本文總結(jié)了reactswiper@6.x版本的使用方法和配置,包括安裝步驟和配置自動(dòng)輪播及移入停止的選項(xiàng),感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • React?Hook?Form?優(yōu)雅處理表單使用指南

    React?Hook?Form?優(yōu)雅處理表單使用指南

    這篇文章主要為大家介紹了React?Hook?Form?優(yōu)雅處理表單使用指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03

最新評(píng)論